summaryrefslogtreecommitdiffstats
path: root/src/lib/ppc405lib
diff options
context:
space:
mode:
authorWilliam Bryan <wilbryan@us.ibm.com>2015-08-03 12:38:58 -0500
committerWilliam A. Bryan <wilbryan@us.ibm.com>2015-08-03 15:32:27 -0500
commit420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3 (patch)
treec9f6691eddba39193e39aa769367e1267fb9fc86 /src/lib/ppc405lib
parentadade8c8ef30ed519322674c762d95663009c5d4 (diff)
downloadtalos-occ-420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3.tar.gz
talos-occ-420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3.zip
new ssx and lib files
Change-Id: I2328b1e86d59e3788910687d762fb70ec680058f Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/19503 Reviewed-by: William A. Bryan <wilbryan@us.ibm.com> Tested-by: William A. Bryan <wilbryan@us.ibm.com>
Diffstat (limited to 'src/lib/ppc405lib')
-rw-r--r--src/lib/ppc405lib/Makefile57
-rw-r--r--src/lib/ppc405lib/README.txt4
-rw-r--r--src/lib/ppc405lib/assert.c71
-rw-r--r--src/lib/ppc405lib/byte_pool.c1442
-rw-r--r--src/lib/ppc405lib/byte_pool.h166
-rw-r--r--src/lib/ppc405lib/chip_config.h109
-rw-r--r--src/lib/ppc405lib/ctype.c46
-rw-r--r--src/lib/ppc405lib/ctype.h149
-rw-r--r--src/lib/ppc405lib/ctype_table.c302
-rw-r--r--src/lib/ppc405lib/errno.h49
-rw-r--r--src/lib/ppc405lib/fgetc.c112
-rw-r--r--src/lib/ppc405lib/initcall.c70
-rw-r--r--src/lib/ppc405lib/initcall.h116
-rw-r--r--src/lib/ppc405lib/lfsr.c50
-rw-r--r--src/lib/ppc405lib/lfsr.h46
-rw-r--r--src/lib/ppc405lib/libppc405files.mk74
-rw-r--r--src/lib/ppc405lib/libssx.h44
-rw-r--r--src/lib/ppc405lib/mutex.c129
-rw-r--r--src/lib/ppc405lib/mutex.h164
-rw-r--r--src/lib/ppc405lib/periodic_semaphore.c114
-rw-r--r--src/lib/ppc405lib/periodic_semaphore.h152
-rw-r--r--src/lib/ppc405lib/polling.c97
-rw-r--r--src/lib/ppc405lib/polling.h118
-rw-r--r--src/lib/ppc405lib/printf.c703
-rw-r--r--src/lib/ppc405lib/progress.c743
-rw-r--r--src/lib/ppc405lib/progress.h177
-rw-r--r--src/lib/ppc405lib/puts.c119
-rw-r--r--src/lib/ppc405lib/rtx_stdio.c149
-rw-r--r--src/lib/ppc405lib/rtx_stdio.h74
-rw-r--r--src/lib/ppc405lib/rtx_stdio_addresses.h55
-rw-r--r--src/lib/ppc405lib/simics_stdio.c174
-rw-r--r--src/lib/ppc405lib/simics_stdio.h93
-rw-r--r--src/lib/ppc405lib/simics_stdio_addresses.h91
-rw-r--r--src/lib/ppc405lib/sprintf.c136
-rw-r--r--src/lib/ppc405lib/ssx_dump.c233
-rw-r--r--src/lib/ppc405lib/ssx_dump.h82
-rw-r--r--src/lib/ppc405lib/ssx_io.c335
-rw-r--r--src/lib/ppc405lib/ssx_io.h228
-rw-r--r--src/lib/ppc405lib/stdlib.c115
-rw-r--r--src/lib/ppc405lib/strcasecmp.c90
-rw-r--r--src/lib/ppc405lib/strdup.c63
-rw-r--r--src/lib/ppc405lib/string_stream.c410
-rw-r--r--src/lib/ppc405lib/string_stream.h277
-rw-r--r--src/lib/ppc405lib/strtox.c617
-rw-r--r--src/lib/ppc405lib/strtox.h151
-rw-r--r--src/lib/ppc405lib/sxlock.c494
-rw-r--r--src/lib/ppc405lib/sxlock.h108
-rw-r--r--src/lib/ppc405lib/time.c82
48 files changed, 9480 insertions, 0 deletions
diff --git a/src/lib/ppc405lib/Makefile b/src/lib/ppc405lib/Makefile
new file mode 100644
index 0000000..37ef2ea
--- /dev/null
+++ b/src/lib/ppc405lib/Makefile
@@ -0,0 +1,57 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/lib/ppc405lib/Makefile $
+#
+# OpenPOWER OnChipController Project
+#
+# Contributors Listed Below - COPYRIGHT 2015
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+# IBM_PROLOG_END_TAG
+# This Makefile currently builds a single archive, 'libppc405.a', from
+# various library source files.
+#
+# part of the complete application build.
+#
+
+#all generated files from this makefile will end up in obj/$(IMAGE_NAME)/ppc405lib
+export SUB_OBJDIR = /ppc405lib
+
+include img_defs.mk
+include libppc405files.mk
+
+OBJS := $(addprefix $(OBJDIR)/, $(LIBPPC405_OBJECTS))
+
+libppc405.a: local
+ $(AR) crs $(OBJDIR)/libppc405.a $(OBJDIR)/*.o
+
+.PHONY: clean
+
+local: $(OBJS)
+
+$(OBJS) $(OBJS:.o=.d): | $(OBJDIR)
+
+$(OBJDIR):
+ mkdir -p $(OBJDIR)
+
+clean:
+ rm -fr $(OBJDIR)
+
+ifneq ($(MAKECMDGOALS),clean)
+#include $(OBJS:.o=.d)
+endif
+
diff --git a/src/lib/ppc405lib/README.txt b/src/lib/ppc405lib/README.txt
new file mode 100644
index 0000000..cc0076f
--- /dev/null
+++ b/src/lib/ppc405lib/README.txt
@@ -0,0 +1,4 @@
+This directory contains all of the library code that only can run on the ppc405.
+For most of the files, the only reason it can not run on the ppe42 is because of
+it's dependence on SSX. Eventually, we would like to fix this so that most, if
+not all files can be made common.
diff --git a/src/lib/ppc405lib/assert.c b/src/lib/ppc405lib/assert.c
new file mode 100644
index 0000000..96143a4
--- /dev/null
+++ b/src/lib/ppc405lib/assert.c
@@ -0,0 +1,71 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/assert.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: assert.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/assert.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file assert.c
+/// \brief Implementation of library routines implied by <assert.h>
+
+#include "ssx.h"
+#include "ssx_io.h"
+#include "libssx.h"
+
+/// The __assert_fail() function is used to implement the assert() interface
+/// of ISO POSIX (2003). The __assert_fail() function prints the given \a
+/// file filename, \a line line number, \a function function name and a
+/// message on the standard error stream then causes a kernel panic. If there
+/// is no standard error stream then the error message is printed on the \a
+/// ssxout (printk()) stream.
+///
+/// If function is NULL, __assert_fail() omits information about the
+/// function. The aguments \a assertion, \a file, and \a line must be
+/// non-NULL.
+
+void
+__assert_fail(const char *assertion,
+ const char *file,
+ unsigned line,
+ const char *function)
+{
+ FILE *stream;
+
+ stream = stderr;
+ if (stream == 0) {
+ stream = ssxout;
+ }
+
+ fprintf(stream, "%s:%u:%s%s Assertion '%s' failed\n",
+ file, line,
+ function ? function : "", function ? ":" : "",
+ assertion);
+
+ SSX_PANIC(ASSERTION_FAILURE);
+}
+
diff --git a/src/lib/ppc405lib/byte_pool.c b/src/lib/ppc405lib/byte_pool.c
new file mode 100644
index 0000000..d382abc
--- /dev/null
+++ b/src/lib/ppc405lib/byte_pool.c
@@ -0,0 +1,1442 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/byte_pool.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id$
+
+/// \file byte_pool.c
+/// \brief An implementation of a constant-time malloc() algorithm.
+///
+/// The 'byte-pool' API defined in this file is similar to ThreadX' byte-pool
+/// operations, with the major difference that here there is no concept of a
+/// thread blocking on memory allocation. This is a concept that is difficult
+/// to implement correctly and efficiently, and several semantic options
+/// exist for how allocation and freeing memory should work in the presence of
+/// blocked threads. The application is always free to implement a blocking
+/// API using these APIs and SSX synchronization primitives.
+///
+/// For convenience this implementation also provides malloc() and calloc()
+/// calls. These APIs depend on the application creating a byte pool and
+/// assigning it to the library variable \a _malloc_byte_pool.
+///
+/// \todo Consider separating the idea of creating a byte pool with a specific
+/// maximum-sized block, from the idea of adding memory to a byte pool. The
+/// idea is to allow pieces of memory required during initialization of the
+/// application to be added back to the pool at run time. We could also
+/// simply add an API to allow memory to be added to a previously created
+/// pool, with the special case that if the block were 'too big' that it would
+/// be split into smaller chunks.
+///
+/// \todo Consider
+/// adding an option to store a pointer to the originating byte pool in the
+/// block header. This would allow deallocation of any block with free()
+/// regardless of which pool it was allocated from, at a cost of 1 pointer per
+/// block. This would simplify some of our validation test cases. We could
+/// also accomplish this by having each pool register ranges of addresses that
+/// it allocates from, but that would require a search every time we freed a
+/// block.
+
+#include "ssx.h"
+#include "byte_pool.h"
+
+// This is an implementation of the TLSF (Two-Level Segregate Fit) algorithm
+// described by M. Masmano, I. Ripoll and A Crespol,
+// http:/rtportal.upv.es/rtmalloc. A couple of their papers and presentations
+// are archived in /lib/doc/tlsf. This is a 'clean-room' implementation of
+// their published ideas based solely on their papers and presentations. No
+// part of their GPL implementation was used to create the byte-pool facility
+// implemented here. The algorithm as implemented here should port without
+// problem to either 32-bit or 64-bit implementations.
+//
+// TLSF has the nice property that it is a constant-time algorithm, both for
+// allocation and freeing allocated blocks. This property is guaranteed by
+// always trading space for speed in the algorithm. This means that we can
+// (and do) run the allocation and freeing in a critical section. With all
+// error checking and statistics, a worst-case byte_bool_alloc() was
+// timed at 318 PowerPC instructions in the PgP OCC (PPC405) Simics
+// simulation. A worst-case byte_pool_free() was timed at 368 PowerPC
+// instructions. These times are expected to equate to ~3us in OCC, a
+// reasonable value for a critical section. [The above times include all
+// error checking].
+//
+// An allocation unit requires two pointers of overhead - a pointer to the
+// previous block and a pointer to the next block (both in terms of linear
+// addresses). The minimum block size also includes the requirement for two
+// extra pointers used to link free blocks into their free lists. The final
+// size of the block (including user data) is simply computed as (next - self)
+// in terms of linear addresses.
+//
+// An allocated block is marked by setting the low-order bit of the 'previous'
+// pointer, which bit is otherwise guaranteed to be 0 due to alignment
+// restrictions. Whenever a block is freed it is immediately merged with the
+// previous and next blocks, if possible. Several places in the block
+// splitting and merging code take advantage of this invariant, and assume
+// that if a block is not already merged with its 'next' partner, then the
+// 'next' partner must be allocated. Sentinel blocks are allocated at either
+// end of the managed area to avoid special checks for the first and last
+// memory blocks during merging.
+//
+// The 'Two-Level' in TLSF refers to the fact that there are multiple free
+// lists arranged in a 2-dimensional array. Each free lists contains blocks
+// that fall into a particular size range. The free list pointers and other
+// data structures described below are carved out of the initial free area
+// when a byte pool is initialized.
+//
+// The first dimension of the free list array is simply the floor(log2(size))
+// of the block. For the second dimension, a tuning parameter selects how many
+// columns each row in the table will contain. The number of columns must be
+// an even power-of-2. Each column represents a fixed power-of-2 size
+// increment of block sizes. Given a block size, it is easy to compute the
+// row and column indices of a free list containing blocks of that size with
+// shifting and masking operation.
+//
+// It is assumed that the C type 'unsigned long' is the same size as a
+// pointer. Therefore the number of rows in the table is less than or equal
+// to the number of bits in an unsigned long. The number of columns is also
+// restricted to being in the range (1, 2, 4, ... number of bits in unsigned
+// long).
+//
+// The above restrictions make it very fast (and constant time) to find a free
+// list that contains a block that will satisfy the allocation request. The
+// byte pool structure maintains a 'row status' word that indicates whether
+// there are any blocks free in any of the free lists of the row. Each row
+// also has an associated 'column status' word that indicates which free lists
+// have blocks free. A row status bit is set if and only if at least one bit
+// in the column status for that row is set.
+//
+// Note that although the 32-bit PowerPC implementation conceptually contains
+// a 32x32 array of free list pointers, only the free list pointers actually
+// required to hold the representable blocks are allocated.
+//
+// The algorithm uses the GCC __builtin_clzl() function to count leading zeros
+// in the status words to find rows/columns that contain free blocks. This
+// generates the 'cntlzw' instruction on 32-bit PowerPC and a similar
+// instruction on X86. So the algorithm is also portable across machines -
+// which simplifies testing.
+//
+// A couple of final facts: When the application requests memory, the block
+// header overhead is added to the request and we look for a free list
+// guaranteed to contain blocks of the requested size. That means that the
+// request size must be rounded up to the next free list size, to avoid having
+// to search a list that might not contain a block of the proper size. This
+// leads to cases where allocation will fail, even though the requested memory
+// is actually available. That's just the price we have to pay for a
+// constant-time guarantee.
+//
+// This memory allocator will never be used in mission-mode for hard-real-time
+// applications, so the statistics are always kept up-to-date. This adds some
+// overhead, but does not effect the constant-time behavior.
+//
+// Given the above description, hopefuly the brief comments with the
+// implementation will make sense.
+
+
+/// The byte pool for use by malloc() and calloc().
+///
+/// The application must define a byte pool and assign it to _malloc_byte_pool
+/// in order for malloc() and calloc() to work.
+
+BytePool *_malloc_byte_pool = 0;
+
+
+// The byte pool memory block header.
+//
+// Each memory block requires 2 pointers of overhead - the pointers to the
+// previous and next (in terms of linear addresses) blocks. The low-order bit
+// of the \a previous pointer is used as the \e allocated flag, and is set
+// when a block is allocated. The size of a block is computed simply as the
+// \a next - \a self. This header layout makes it very simple to merge blocks
+// when they are deallocated.
+
+typedef struct ByteBlock {
+
+ // Pointer to the previous (in terms of linear address) block.
+ //
+ // The low-order bit of the pointer is set to indicate a block that has
+ // been allocated.
+ struct ByteBlock *previous;
+
+ // Pointer to the next (in terms of linear address) block.
+ //
+ // The size of the block is computed simply as \a next - \a self.
+ struct ByteBlock *next;
+
+} ByteBlock;
+
+
+// A free byte-pool memory block
+//
+// Blocks stored in free lists require an additional 2 pointers of
+// overhead. The blocks are doubly-linked in the free lists to make deletion
+// a constant-time operation. Note that the previous pointer is a pointer to
+// a pointer to a ByteBlock - it may be pointing to the free list
+// header. Since all blocks must be freeable, this structure defines the
+// minimum block size.
+
+typedef struct FreeByteBlock {
+
+ // The base object
+ ByteBlock block;
+
+ // Pointer to the next block in the free list
+ struct FreeByteBlock *next;
+
+ // Pointer to the \a next pointer of the previous element in the free
+ // list, or a pointer to the free list header.
+ struct FreeByteBlock **previous;
+
+} FreeByteBlock;
+
+
+// All blocks will be aligned to this size, so this size also defines the
+// minimum quantum of memory allocation. The coice of 8 should give
+// good results for both 32-bit and 64-bit implementations.
+//
+// NB : This implmentation assumes that the ByteBlock and FreeByteBLock are
+// aligned to this alignment - if this constant is ever changed from 8 then
+// the ByteBlock and FreeByteBlock may need to be padded to meet the alignment
+// assumptions, and the \a minimum_block_size may need to be adjusted.
+
+#define ALIGNMENT 8
+
+
+// An unsigned long, big-endian bit mask
+
+#define UL_BE_MASK(i) \
+ ((unsigned long)1 << (BITS_PER_UNSIGNED_LONG - (i) - 1))
+
+
+// Align a value to the alignment. The direction is either positive or
+// negative to indicate alignment up or down.
+
+static inline unsigned long
+align(unsigned long x, int direction)
+{
+ if (x % ALIGNMENT) {
+ if (direction > 0) {
+ return x + (ALIGNMENT - (x % ALIGNMENT));
+ } else {
+ return x - (x % ALIGNMENT);
+ }
+ } else {
+ return x;
+ }
+}
+
+
+// Compute the floor(log2(x)) of x. This is used to compute the row indices
+// of blocks based on the block size.
+
+static inline int
+floor_log2(unsigned long x)
+{
+ return BITS_PER_UNSIGNED_LONG - 1 - __builtin_clzl(x);
+}
+
+
+// In theory the tuning parameters might vary based on the amount of memory
+// being managed, but for now we simply use constants.
+//
+// The minimum block size includes both the size of the header, as well as the
+// requirement that the number of columns be <= the mimumum block size to make
+// the addressing uniform. For example, on PPC405 the minimum block size is 16
+// bytes (4 pointers) -- unless the number of columns is 32, in which case it
+// has to grow to 32 bytes.
+//
+// Note that no matter what, we may allocate free list pointers in the
+// lower-numbered rows that will never be populated due to alignment
+// constraints.
+
+#ifndef BYTE_POOL_TLSF_COLUMNS
+#define BYTE_POOL_TLSF_COLUMNS 8 /* 1,2,4, ... BITS_PER_UNSIGNED_LONG */
+#endif
+
+static void
+compute_tuning(BytePool *pool, size_t size, int columns)
+{
+ int log2_min_size;
+
+ pool->columns = columns;
+ pool->log2_columns = floor_log2(pool->columns);
+ pool->column_mask = (1 << pool->log2_columns) - 1;
+
+ log2_min_size = MAX(pool->log2_columns, floor_log2(sizeof(FreeByteBlock)));
+ pool->minimum_block_size = align(1 << log2_min_size, 1);
+}
+
+
+// Compute the size of a block
+
+static inline size_t
+block_size(ByteBlock *block)
+{
+ return (unsigned long)(block->next) - (unsigned long)block;
+}
+
+
+/// Return implementation information for a block
+///
+/// \param memory The memory block to query. This pointer must have been
+/// returned by one of the byte_pool functions or derivitives, or may also be
+/// 0.
+///
+/// \param actual_address : Returned as the address of the block header.
+///
+/// \param actual_size Returned as the size of the complete block, including
+/// the header.
+///
+/// \param useful_size : Returned as the actual amount of space available from
+/// \a memory to the end of the block. The \a useful_size may be useful to
+/// applications that allocate big blocks then carve them up into smaller
+/// structures.
+///
+/// Note that any of \a actual_address, \a actual_size and \a useful_size may
+/// be passed in as 0 if the caller does not require the information.
+
+void
+byte_pool_block_info(void* memory,
+ void** actual_address, size_t* actual_size,
+ size_t* useful_size)
+{
+ ByteBlock* block;
+
+ if (memory == 0) {
+
+ if (actual_address) *actual_address = 0;
+ if (actual_size) *actual_size = 0;
+ if (useful_size) *useful_size = 0;
+
+ } else {
+
+ // This implementation uses the convention that if the \a next pointer
+ // of the putative ByteBlock == 1, then this is actually an aligned
+ // allocation and the actual ByteBlock is located at the address
+ // contained in the \a previous field of the dummy header.
+
+ block = (ByteBlock *)(((unsigned long)memory) - sizeof(ByteBlock));
+ if ((int)(block->next) == 1) {
+ block = block->previous;
+ }
+
+ if (actual_address) *actual_address = block;
+ if (actual_size) *actual_size = block_size(block);
+ if (useful_size)
+ *useful_size =
+ (unsigned long)(block->next) - (unsigned long)memory;
+ }
+}
+
+
+// Mark a block as allocated by setting the low-order bit of the \a previous
+// pointer.
+
+static inline ByteBlock *
+allocated(ByteBlock *p)
+{
+ return (ByteBlock *)((unsigned long)p | 1ul);
+}
+
+
+static void
+mark_allocated(BytePool *pool, ByteBlock *block)
+{
+ size_t bytes = block_size(block);
+
+ pool->bytes_allocated += bytes;
+ pool->bytes_free -= bytes;
+ pool->blocks_allocated += 1;
+ pool->blocks_free -= 1;
+
+ block->previous = allocated(block->previous);
+}
+
+
+// Mark a block as free by clearing the low-order bit of the \a previous
+// pointer.
+
+static inline ByteBlock *
+deallocated(ByteBlock *p)
+{
+ return (ByteBlock *)((unsigned long)p & ~1ul);
+}
+
+
+static void
+mark_free(BytePool *pool, ByteBlock *block)
+{
+ size_t bytes = block_size(block);
+
+ pool->bytes_allocated -= bytes;
+ pool->bytes_free += bytes;
+ pool->blocks_allocated -= 1;
+ pool->blocks_free += 1;
+
+ block->previous = deallocated(block->previous);
+}
+
+
+// Check for a block being free
+
+static inline int
+block_is_free(ByteBlock *block)
+{
+ return (((unsigned long)(block->previous)) & 1ul) == 0;
+}
+
+
+// Normalize a 'previous' pointer
+
+static inline ByteBlock *
+normalize_previous(ByteBlock *previous)
+{
+ return (ByteBlock *)((unsigned long)previous & ~1ul);
+}
+
+
+// Check for correct linkage. This is such a critical check for application
+// memory corruption that it is always done.
+
+static int
+check_linkage(ByteBlock *block)
+{
+ if (normalize_previous(block->next->previous) != block) {
+ printk("byte_pool: Forward linkage error\n"
+ " block : %p\n"
+ " block->next : %p\n"
+ " block->next->previous : %p\n",
+ block,
+ block->next,
+ block->next->previous);
+ SSX_ERROR(BYTE_POOL_REVERSE_LINKAGE);
+ } else if (normalize_previous(block->previous)->next != block) {
+ printk("byte_pool: linkage error\n"
+ " block->previous : %p\n"
+ " block->pevious->next : %p\n"
+ " block : %p\n",
+ block->previous,
+ block->previous->next,
+ block);
+ SSX_ERROR(BYTE_POOL_FORWARD_LINKAGE);
+ }
+ return 0;
+}
+
+
+// Mark a free list as empty
+
+static inline void
+mark_empty(BytePool *pool, int row, int column)
+{
+ pool->column_status[row] &= ~UL_BE_MASK(column);
+ if (pool->column_status[row] == 0) {
+ pool->row_status &= ~UL_BE_MASK(row);
+ }
+}
+
+
+// Mark a free list as non-empty
+
+static inline void
+mark_non_empty(BytePool *pool, int row, int column)
+{
+ pool->column_status[row] |= UL_BE_MASK(column);
+ pool->row_status |= UL_BE_MASK(row);
+}
+
+
+// Convert a size into row and column indices
+
+static inline void
+size2rc(BytePool *pool, size_t size, int *row, int *column)
+{
+ *row = floor_log2(size);
+ *column = (size >> (*row - pool->log2_columns)) & pool->column_mask;
+}
+
+
+// Given a block size, find the free list that contains blocks of that size
+// (or greater, up to the next free list). When called during block freeing,
+// the block size is known to be valid. When called during allocation, the
+// block size may be invalid (too big), in which case 0 is returned.
+
+static FreeByteBlock **
+find_free_list(BytePool *pool, size_t size, int *row, int *column)
+{
+ size2rc(pool, size, row, column);
+ if (*row > pool->last_row) {
+ return 0;
+ }
+ return &((pool->free[*row])[*column]);
+}
+
+
+// Remove an arbitrary block from its free list due to a merging operation.
+
+static void
+unlink_free_block(BytePool *pool, ByteBlock *block)
+{
+ FreeByteBlock **free_list;
+ FreeByteBlock *free_block;
+ int row, column;
+
+ free_list = find_free_list(pool, block_size(block), &row, &column);
+
+ if (SSX_ERROR_CHECK_KERNEL) {
+ if (free_list == 0) {
+ SSX_PANIC(BYTE_POOL_NULL_FREE_LIST);
+ }
+ }
+
+ // Unlink the block from the free list
+
+ free_block = (FreeByteBlock *)block;
+ *(free_block->previous) = free_block->next;
+ if (free_block->next) {
+ free_block->next->previous = free_block->previous;
+ }
+
+ // If the free list is now 0, mark the free list as empty.
+
+ if (*free_list == 0) {
+ mark_empty(pool, row, column);
+ }
+}
+
+
+// Link a block into the head of its free list due to freeing memory
+
+static void
+link_free_block(BytePool *pool, ByteBlock *block)
+{
+ FreeByteBlock **free_list;
+ FreeByteBlock *free_block;
+ int row, column;
+
+ free_list = find_free_list(pool, block_size(block), &row, &column);
+
+ if (SSX_ERROR_CHECK_KERNEL) {
+ if (free_list == 0) {
+ SSX_PANIC(BYTE_POOL_NULL_FREE_LIST);
+ }
+ }
+
+ // Link the block into the free list, and mark the free list as
+ // non-empty.
+
+ free_block = (FreeByteBlock *)block;
+
+ free_block->next = *free_list;
+ if (*free_list) {
+ (*free_list)->previous = &(free_block->next);
+ }
+ *free_list = free_block;
+ free_block->previous = free_list;
+
+ mark_non_empty(pool, row, column);
+}
+
+
+// Round up the block size (if required) to the next column. Note that the
+// block_size input here is aligned, and remains aligned even after rounding.
+
+static size_t
+round_up_size(BytePool *pool, size_t block_size)
+{
+ size_t residue, column_span, column_mask;
+ int row = floor_log2(block_size);
+
+ column_span = 1 << (row - pool->log2_columns);
+ column_mask = column_span - 1;
+ residue = block_size & column_mask;
+
+ if (residue == 0) {
+ return block_size;
+ } else {
+ return block_size + (column_span - residue);
+ }
+}
+
+
+// The implemenation of freeing a block of memory. When freed, a block is
+// immediately merged with its neighbors if possible, and the final merged
+// block is inserted into the proper free list.
+//
+// The linkage check is done here so that it can also protect internal uses of
+// this API (but only if SSX errors lead to panics, the expected default).
+
+static int
+byte_pool_free_block(BytePool *pool, ByteBlock *block)
+{
+ int rc;
+ SsxMachineContext ctx;
+
+ rc = check_linkage(block);
+ if (rc) return rc;
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ pool->free_calls++;
+
+ mark_free(pool, block);
+
+ if (block_is_free(block->next)) {
+
+ // Merge next block into current block
+
+ unlink_free_block(pool, block->next);
+
+ block->next = (ByteBlock *)((unsigned long)(block->next) +
+ block_size(block->next));
+ block->next->previous = allocated(block);
+
+ pool->blocks_free--;
+ }
+
+ if (block_is_free(block->previous)) {
+
+ // Merge current block into previous block
+
+ unlink_free_block(pool, block->previous);
+
+ block->previous->next =
+ (ByteBlock *)((unsigned long)(block->previous->next) +
+ block_size(block));
+ block = block->previous;
+ block->next->previous = allocated(block);
+
+ pool->blocks_free--;
+ }
+
+ // Finally, insert the block into the proper free list.
+
+ link_free_block(pool, block);
+
+ ssx_critical_section_exit(&ctx);
+
+ return 0;
+}
+
+
+/// Free a block of memory back to a byte pool
+///
+/// \param pool A pointer to the BytePool structure that allocated the memory.
+///
+/// \param memory A pointer to memory returned by byte_pool_alloc() or
+/// byte_pool_alloc_aligned() for the pool. This pointer may be NULL (0), in
+/// which case the byte_pool_free() request succeeds immediately.
+///
+/// The part of this API that manipulates the \a pool runs as an
+/// SSX_NONCRITICAL critical section. byte_pool_free() uses a constant-time
+/// algorithm.
+///
+/// Return values other then SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Success
+///
+/// \retval -BYTE_POOL_INVALID_OBJECT The \a pool argument was NULL (0).
+///
+/// \retval -BYTE_POOL_INVALID_ARGUMENT The block is not marked as being
+/// allocated, or does not appear to have been allocated from this byte_pool.
+///
+/// \retval -BYTE_POOL_LINKAGE_ERROR The block being freed is not linked
+/// correctly with the other blocks managed by the pool, most likely
+/// indicating that the memory being freed was not allocated by
+/// byte_pool_alloc(), or that memory corruption has occured.
+
+// This implementation uses the convention that if the \a next pointer of the
+// putative ByteBlock == 1, then this is actually an aligned allocation and
+// the actual ByteBlock is located at the address contained in the \a previous
+// field of the dummy header.
+
+int
+byte_pool_free(BytePool *pool, void *memory)
+{
+ ByteBlock *block;
+
+ if (memory == 0) {
+ return 0;
+ }
+
+ block = (ByteBlock *)(((unsigned long)memory) - sizeof(ByteBlock));
+ if ((int)(block->next) == 1) {
+ if (0) {
+ printk("byte_pool_free(%p, %p) [%p] : Aligned\n",
+ pool, memory, block);
+ }
+ block = block->previous;
+ }
+
+ if (0) {
+ printk("byte_pool_free(%p, %p) [%p] : %d %d %d\n",
+ pool, memory, block,
+ block_is_free(block),
+ block < pool->first_block,
+ block > pool->last_block);
+ }
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(pool == 0, BYTE_POOL_INVALID_OBJECT);
+ SSX_ERROR_IF(block_is_free(block) ||
+ (block < pool->first_block) ||
+ (block > pool->last_block),
+ BYTE_POOL_INVALID_ARGUMENT);
+ }
+
+ return byte_pool_free_block(pool, block);
+}
+
+
+/// Create a BytePool with explicit specification of tuning parameters
+///
+/// This routine is the real body of byte_pool_create(), however this
+/// underlying interface is provided for testing and experimentation and allows
+/// the specification of non-default tuning parameters.
+///
+/// There is actually only one tuning parameter for TLSF - the number of
+/// columns. The number of columns must be an even power of two no larger
+/// than the number of bits in an unsigned long.
+///
+/// Return values other then SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval -BYTE_POOL_INVALID_OBJECT The \a pool pointer was NULL (0).
+///
+/// \retval -BYTE_POOL_INVALID_ARGUMENT Either the \a memory pointer was NULL
+/// (0), the amount of memory was insufficient for the management overhead, or
+/// the parameterization was invalid.
+
+int
+byte_pool_create_tuned(BytePool *pool, void *memory, size_t size,
+ int columns)
+{
+ size_t overhead, free_list_overhead;
+ unsigned long memory_ul, aligned_memory;
+ int i;
+ FreeByteBlock **free;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(pool == 0, BYTE_POOL_INVALID_OBJECT);
+ SSX_ERROR_IF((memory == 0) ||
+ (columns < 1) ||
+ ((columns & (columns - 1)) != 0) ||
+ (floor_log2(columns) > floor_log2(BITS_PER_UNSIGNED_LONG)),
+ BYTE_POOL_INVALID_ARGUMENT);
+ }
+
+ // Compute tuning parameters
+
+ compute_tuning(pool, size, columns);
+
+ // Clear free list vector pointers and column status
+
+ for (i = 0; i < BITS_PER_UNSIGNED_LONG; i++) {
+ pool->free[i] = 0;
+ pool->column_status[i] = 0;
+ }
+
+ // Determine the first and last allocated rows.
+
+ pool->first_row = floor_log2(pool->minimum_block_size);
+ pool->last_row = floor_log2(size);
+
+ // The dynamic overhead consists of aligment overhead, 2 sentinel nodes,
+ // the vectors of pointers to free lists, plus 2 alignments. There must
+ // also be enough room for at least 1 block to allocate.
+
+ memory_ul = (unsigned long)memory;
+ aligned_memory = align(memory_ul, 1);
+
+ free_list_overhead =
+ (((pool->last_row - pool->first_row + 1) * pool->columns) *
+ sizeof(FreeByteBlock *));
+
+ overhead =
+ (aligned_memory - memory_ul) +
+ (2 * sizeof(ByteBlock)) +
+ free_list_overhead +
+ (2 * ALIGNMENT) +
+ pool->minimum_block_size;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(overhead >= size, BYTE_POOL_INVALID_ARGUMENT);
+ }
+
+ // Allocate the overhead items. The free list vectors and column status
+ // arrays are carved out and zeroed. For good measure we re-align after
+ // each of these operations. The sentinel blocks are carved off of either
+ // end of the remaining free space and marked allocated. The remaining
+ // initial "big block" is also initialized (as if it were allocated).
+
+ size = size - (aligned_memory - memory_ul);
+ size = align(size, -1);
+
+ pool->row_status = 0;
+
+ free = (FreeByteBlock **)aligned_memory;
+ memset((void *)free, 0, free_list_overhead);
+
+ aligned_memory += free_list_overhead;
+ size -= free_list_overhead;
+ aligned_memory = align(aligned_memory, 1);
+ size = align(size, -1);
+
+ for (i = pool->first_row; i <= pool->last_row; i++) {
+ pool->free[i] = free;
+ free += pool->columns;
+ }
+
+ pool->first_block = (ByteBlock *)aligned_memory;
+ aligned_memory += sizeof(ByteBlock);
+ size -= sizeof(ByteBlock);
+
+ pool->big_block = (ByteBlock *)aligned_memory;
+
+ pool->last_block =
+ (ByteBlock *)(aligned_memory + size - sizeof(ByteBlock));
+ size -= sizeof(ByteBlock);
+
+ pool->first_block->next = pool->big_block;
+ pool->first_block->previous = 0;
+ mark_allocated(pool, pool->first_block);
+
+ pool->last_block->next = 0;
+ pool->last_block->previous = pool->big_block;
+ mark_allocated(pool, pool->last_block);
+
+ pool->big_block->previous = pool->first_block;
+ pool->big_block->next = pool->last_block;
+
+ // Initialize statistics
+
+ pool->bytes_allocated = 0;
+ pool->bytes_free = block_size(pool->big_block);
+ pool->initial_allocation = pool->bytes_free;
+ pool->blocks_allocated = 0;
+ pool->blocks_free = 1;
+ pool->alloc_calls = 0;
+ pool->free_calls = 0;
+
+ // Free the big block and we're ready to go.
+
+ mark_allocated(pool, pool->big_block);
+ byte_pool_free_block(pool, pool->big_block);
+
+ return 0;
+}
+
+
+/// Create a BytePool
+///
+/// \param pool A pointer to an uninitialized BytePool structure
+///
+/// \param memory A pointer to the memory to be managed by the BytePool
+///
+/// \param size The size of the managed area in bytes
+///
+/// byte_pool_create() sets up the \a memory area to be used as a memory pool
+/// for malloc()-style allocation using byte_pool_alloc() and
+/// byte_pool_free(). Note that the actual memory area available for
+/// allocation will be smaller than \a size due to alignment, and reservation
+/// of a portion of the area for management overhead.
+///
+/// Return values other then SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval -BYTE_POOL_INVALID_OBJECT The \a pool pointer was NULL (0).
+///
+/// \retval -BYTE_POOL_INVALID_ARGUMENT Either the \a memory pointer was NULL
+/// (0), the amount of memory was insufficient for the management overhead, or
+/// the parameterization was invalid.
+
+int
+byte_pool_create(BytePool *pool, void *memory, size_t size)
+{
+ return byte_pool_create_tuned(pool, memory, size, BYTE_POOL_TLSF_COLUMNS);
+}
+
+
+/// Allocate memory from a byte pool
+///
+/// \param pool A pointer to an initialized BytePool
+///
+/// \param memory An address to recieve a pointer to the allocated memory.
+/// This address will be set to NULL (0) if the allocation request can not be
+/// satisfied (or the \a size is 0).
+///
+/// \param size The number of bytes to allocate.
+///
+/// The part of this API that manipulates the \a pool runs as an
+/// SSX_NONCRITICAL critical section. byte_pool_alloc() uses a constant-time
+/// algorithm.
+///
+/// Return values other than 0 are not necessarily errors; see \ref
+/// ssx_errors.
+///
+/// The following return codes are not considered errors:
+///
+/// \retval 0 Success
+///
+/// \retval -BYTE_POOL_NO_MEMORY The allocation request could not be
+/// satisfied. The memory pointer will also be NULL (0) in this case.
+///
+/// The following return codes are considered errors:
+///
+/// \retval -BYTE_POOL_INVALID_OBJECT The \a pool argument was NULL (0).
+///
+/// \retval -BYTE_POOL_INVALID_ARGUMENT The \a memory argument is NULL (0).
+
+int
+byte_pool_alloc(BytePool *pool, void **memory, size_t size)
+{
+ SsxMachineContext ctx;
+ size_t request_size, actual_size;
+ int found, row, column;
+ unsigned long row_status, column_status;
+ FreeByteBlock **free_list;
+ FreeByteBlock *free_block;
+ ByteBlock *block;
+ ByteBlock *residue_block;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(pool == 0, BYTE_POOL_INVALID_OBJECT);
+ SSX_ERROR_IF(memory == 0, BYTE_POOL_INVALID_ARGUMENT);
+ }
+
+ // Quickly dispense with NULL requests
+
+ if (size == 0) {
+ *memory = 0;
+ return 0;
+ }
+
+ // Compute the requested block size (which includes the header). If the
+ // size went down we overflowed due to a huge request (which can't be
+ // filled). Otherwise if the request is small it is boosted up to the
+ // (aligned) minimum size. To guarantee fast search, the requested size
+ // must then be rounded up to a size that is represented in the 2-D array
+ // of free list pointers.
+
+ request_size = align(size + sizeof(ByteBlock), 1);
+ if (request_size < size) {
+ *memory = 0;
+ return -BYTE_POOL_NO_MEMORY;
+ }
+
+ if (request_size < pool->minimum_block_size) {
+ request_size = pool->minimum_block_size;
+ }
+
+ request_size = round_up_size(pool, request_size);
+
+ // Up to this point, all accesses of the memory pool object have been to
+ // read only constants. Now we get serious.
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ pool->alloc_calls++;
+
+ // See if a block of the correct or larger size exists in the row. The
+ // search is first via a single bit in the row_status. If that hits then
+ // we check for columns >= the target column.
+
+ found = 0;
+ size2rc(pool, request_size, &row, &column);
+
+ if (pool->row_status & UL_BE_MASK(row)) {
+
+ column_status = pool->column_status[row] &
+ ((UL_BE_MASK(column) << 1) - 1);
+
+ if (column_status != 0) {
+ column = __builtin_clzl(column_status);
+ found = 1;
+ }
+ }
+
+ // If the block was not found in the 'optimum' row, look in all rows of
+ // larger size and take the first block that fits.
+
+ if (!found) {
+
+ row_status = pool->row_status & (UL_BE_MASK(row) - 1);
+
+ if (row_status != 0) {
+ row = __builtin_clzl(row_status);
+ column = __builtin_clzl(pool->column_status[row]);
+ found = 1;
+ }
+ }
+
+ // Another out of memory case.
+
+ if (!found) {
+ ssx_critical_section_exit(&ctx);
+ *memory = 0;
+ return -BYTE_POOL_NO_MEMORY;
+ }
+
+ // Now we can get the pointer to the free list and take the block.
+
+ free_list = &((pool->free[row])[column]);
+
+ if (SSX_ERROR_CHECK_KERNEL) {
+ if ((free_list == 0) || (*free_list == 0)) {
+ SSX_PANIC(BYTE_POOL_INVALID_FREE_LIST);
+ }
+ }
+
+ free_block = *free_list;
+ *free_list = free_block->next;
+ if (free_block->next) {
+ free_block->next->previous = free_list;
+ } else {
+ mark_empty(pool, row, column);
+ }
+
+ // Mark the block as allocated
+
+ block = (ByteBlock *)free_block;
+ mark_allocated(pool, block);
+
+ // If there is enough residue, split the excess memory off of the end of
+ // the block. This is a kind of dummy transaction for our statistical
+ // purposes.
+
+ actual_size = block_size(block);
+ if ((actual_size - request_size) >= pool->minimum_block_size) {
+
+ residue_block = (ByteBlock *)((unsigned long)block + request_size);
+
+ residue_block->next = block->next;
+ residue_block->previous = block;
+ residue_block->previous->next = residue_block;
+ residue_block->next->previous = allocated(residue_block);
+
+ pool->blocks_allocated++;
+ byte_pool_free_block(pool, residue_block);
+ pool->free_calls--;
+ }
+
+ // Set the memory pointer to the area to be used by the application and
+ // return.
+
+ *memory = (void *)((unsigned long)block + sizeof(ByteBlock));
+
+ ssx_critical_section_exit(&ctx);
+
+ if (0) {
+ ByteBlock* block =
+ (ByteBlock*)((unsigned long)*memory - sizeof(ByteBlock));
+
+ printk("byte_pool_alloc(%p, -> %p, %zu)\n"
+ " request_size = %u, Previous = %p, Next = %p\n",
+ pool, *memory, size,
+ request_size, block->previous, block->next);
+ }
+
+ return 0;
+}
+
+
+/// Allocate memory from a byte pool and clear
+///
+/// byte_pool_calloc() allocates memory using byte_pool_alloc() then clears
+/// the memory area using memset(). The arguments conform to the POSIX
+/// standard for calloc(). See byte_pool_alloc() for return codes and usage
+/// notes.
+
+int
+byte_pool_calloc(BytePool *pool, void **memory, size_t nmemb, size_t size)
+{
+ int rc;
+
+ rc = byte_pool_alloc(pool, memory, nmemb * size);
+ if (rc || (*memory == 0)) {
+ return rc;
+ }
+
+ memset(*memory, 0, nmemb * size);
+
+ return 0;
+}
+
+
+/// Allocate an aligned memory area
+///
+/// \param pool A pointer to an initialized BytePool
+///
+/// \param memory An address to recieve a pointer to the allocated memory.
+/// This address will be set to NULL (0) if the allocation request can not be
+/// satisfied (or the \a size is 0).
+///
+/// \param size The size of the memory area required (in bytes). This can be
+/// any size - it \e does \e not have to be a multiple of the aligned size (as
+/// is required by other common aligned memory allocators).
+///
+/// \param alignment The alignment constraint, specified as the base 2
+/// logarithm of the alignment. For example, to align on a 128-byte boundary
+/// the \a alignment would be specified as 7.
+///
+/// byte_pool_alloc_aligned() is a convenience interface for allocating memory
+/// with a guaranteed alignment. The BytePool APIs do not normally do aligned
+/// allocation. byte_pool_alloc_aligned() first uses byte_pool_alloc() to
+/// allocate a block of memory large enough to satisfy the request and
+/// guarantee that a subset of the memory allocation will satisfy the
+/// alignment constraint plus the overhead of a dummy block header. Note that
+/// it is space-inefficient to allocate many small aligned areas. If possble
+/// it would be better to allocate a single aligned area and then have the
+/// application partition the memory as required.
+///
+/// Memory areas allocated by byte_pool_alloc_aligned() can be freed with
+/// byte_pool_free(), just like any other dynamic memory allocation.
+///
+/// The part of this API that manipulates the \a pool runs as an
+/// SSX_NONCRITICAL critical section. The underlying call of byte_pool_alloc()
+/// uses a constant-time algorithm.
+///
+/// Return values other than 0 are not necessarily errors; see \ref
+/// ssx_errors.
+///
+/// The following return codes are not considered errors:
+///
+/// \retval 0 Success
+///
+/// \retval -BYTE_POOL_NO_MEMORY The allocation request could not be
+/// satisfied. The memory pointer will also be NULL (0) in this case.
+///
+/// The following return codes are considered errors:
+///
+/// \retval -BYTE_POOL_INVALID_OBJECT The \a pool argument was NULL (0).
+///
+/// \retval -BYTE_POOL_INVALID_ARGUMENT The \a memory argument is NULL (0), or
+/// the \a alignment argument is invalid.
+
+// The allocation must be big enough for the size requested + the alignment
+// amount (to guarantee alignment) + room for a dummy ByteBlock. The dummy
+// ByteBlock is marked by setting the \a next pointer to 1 to indicate that
+// this is an aligned allocation. In this case the \a previous pointer of the
+// dummy ByteBlock points to the ByteBlock of the original allocation.
+
+int
+byte_pool_alloc_aligned(BytePool *pool, void **memory, size_t size,
+ int alignment)
+{
+ int rc;
+ unsigned long pow2_alignment, mask, aligned;
+ void *unaligned_memory;
+ ByteBlock *dummy_block, *unaligned_block;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF((alignment < 1) || (alignment >= BITS_PER_UNSIGNED_LONG),
+ BYTE_POOL_INVALID_ARGUMENT);
+ }
+
+ pow2_alignment = (unsigned long)1 << (unsigned long)alignment;
+ mask = pow2_alignment - 1;
+
+ rc = byte_pool_alloc(pool, &unaligned_memory,
+ size + pow2_alignment + sizeof(ByteBlock));
+
+ if (rc || (unaligned_memory == 0)) {
+ *memory = 0;
+ return rc;
+ }
+ unaligned_block = (ByteBlock *)(((unsigned long)unaligned_memory) -
+ sizeof(ByteBlock));
+
+ aligned = (unsigned long)unaligned_memory + sizeof(ByteBlock);
+ if (aligned & mask) {
+ aligned += (pow2_alignment - (aligned & mask));
+ }
+ *memory = (void *)aligned;
+
+ dummy_block = (ByteBlock *)(aligned - sizeof(ByteBlock));
+ dummy_block->previous = unaligned_block;
+ dummy_block->next = (ByteBlock*)1;
+
+ if (0) {
+ printk("byte_pool_alloc_aligned(%p, -> %p, %zu, %d)\n",
+ pool, *memory, size, alignment);
+ }
+
+ return 0;
+}
+
+
+/// Allocate aligned memory from a byte pool and clear
+///
+/// byte_pool_calloc_alligned() allocates memory using
+/// byte_pool_alloc_aligned() then clears the memory area using memset(). The
+/// arguments conform to the POSIX standard for calloc(). See
+/// byte_pool_alloc_aligned() for return codes and usage notes. In particular
+/// note that this memory must be freed with byte_pool_free_aligned().
+
+int
+byte_pool_calloc_aligned(BytePool *pool, void **memory,
+ size_t nmemb, size_t size, int alignment)
+{
+ int rc;
+
+ rc = byte_pool_alloc_aligned(pool, memory, nmemb * size, alignment);
+ if (rc || (*memory == 0)) return rc;
+
+ memset(*memory, 0, nmemb * size);
+
+ return 0;
+}
+
+
+/// malloc() allocates \a size bytes and returns a pointer to the allocated
+/// memory. The memory is not cleared. The value returned is a pointer to the
+/// allocated memory, which is suitably aligned for any kind of variable, or
+/// NULL if the requested \a size is 0 or the request fails.
+///
+/// NB: The aplication must create and assign a BytePool object to the
+/// library variable _malloc_byte_pool in order for malloc() to work.
+
+void *
+malloc(size_t size)
+{
+ void *memory;
+
+ if (byte_pool_alloc(_malloc_byte_pool, &memory, size)) {
+ memory = 0;
+ }
+ return memory;
+}
+
+
+/// calloc() allocates memory for an array of \a nmemb elements of \a size
+/// bytes each and returns a pointer to the allocated memory. The memory is
+/// set to zero. The value returned is a pointer to the allocated and cleared
+/// memory, which is suitably aligned for any kind of variable, or NULL if the
+/// requested \a size is 0 or the request fails.
+///
+/// NB: The aplication must create and assign a BytePool object to the
+/// library variable _malloc_byte_pool in order for calloc() to work.
+
+void *
+calloc(size_t nmemb, size_t size)
+{
+ void *memory;
+
+ if (byte_pool_calloc(_malloc_byte_pool, &memory, nmemb, size)) {
+ return 0;
+ }
+ return memory;
+}
+
+
+/// free() frees the memory space pointed to by \a ptr, which must have been
+/// returned by a previous call to malloc(), posix_memalign, calloc() or
+/// realloc(). Otherwise, or if free(ptr) has already been called before,
+/// undefined behavior occurs. If \a ptr is NULL, no operation is performed.
+///
+/// NB: The aplication must create and assign a BytePool object to the
+/// library variable _malloc_byte_pool in order for free() to work.
+
+void
+free(void *ptr)
+{
+ byte_pool_free(_malloc_byte_pool, ptr);
+}
+
+
+/// realloc() changes the size of the memory block pointed to by \a ptr to \a
+/// size bytes. The contents will be unchanged to the minimum of the old and
+/// new sizes; newly allocated memory will be uninitialized. If \a ptr is
+/// NULL, the call is equivalent to malloc(size); if \a size is equal to zero,
+/// the call is equivalent to free(ptr). Unless \a ptr is NULL, it must have
+/// been returned by an earlier call to malloc(), calloc() or realloc(). If
+/// the area pointed to was moved, a free(ptr) is done.
+///
+/// realloc() returns a pointer to the newly allocated memory, which is
+/// suitably aligned for any kind of variable and may be different from \a
+/// ptr, or NULL if the request fails. If \a size was equal to 0, either NULL
+/// or a pointer suitable to be passed to free() is returned. If realloc()
+/// fails the original block is left untouched; it is not freed or moved.
+
+void*
+realloc(void *ptr, size_t size)
+{
+ void *memory;
+ size_t useful_size;
+
+ // Handle simple case
+
+ if (ptr == 0) {
+
+ memory = malloc(size);
+
+ } else if (size == 0) {
+
+ free(ptr);
+ memory = 0;
+
+ } else {
+
+ // Find out the useful size of the block. If we need more than this we
+ // need to allocate a new block and memcpy() the old data to the new
+ // block and free the old block. If we need less then this we also
+ // need to allocate a new block and move the head of the current
+ // data. If the new size is the same as the current size we do nothing.
+
+ byte_pool_block_info(ptr, 0, 0, &useful_size);
+
+ if (size == useful_size) {
+
+ memory = ptr;
+
+ } else {
+
+ memory = malloc(size);
+ if (memory != 0) {
+ memcpy(memory, ptr, (size > useful_size) ? useful_size : size);
+ free(ptr);
+ }
+ }
+ }
+ return memory;
+}
+
+
+/// The posix_memalign() function allocates \a size bytes aligned on a
+/// boundary specified by \a alignment, and returns a pointer to the allocated
+/// memory in \a memptr. The value of \a alignment shall be a multiple of
+/// sizeof(void*), that is also a power of two. Upon successful completion,
+/// the value pointed to by \a memptr will be a multiple of alignment.
+///
+/// Note that memory allocated with posix_memalign() can be freed with
+/// free().
+///
+/// In the event of errors, the contents of \a memptr will be returned as 0.
+///
+/// The following return codes are mandated by POSIX, and are always returned
+/// in the event of the specified condition.
+///
+/// \retval 0 Success
+///
+/// \retval -EINVAL The value of the \a alignment parameter is not a power of
+/// two multiple of sizeof(void*).
+///
+/// \retval -ENOMEM There is insufficient memory available with the requested
+/// alignment.
+///
+/// The following return codes are implementation-specific and may be
+/// configured to cause a kernel panic.
+///
+/// \retval -BYTE_POOL_INVALID_OBJECT The \a _malloc_byte_pool is NULL (0).
+///
+/// \retval -BYTE_POOL_INVALID_ARGUMENT The \a memptr argument is NULL (0).
+
+int
+posix_memalign(void** memptr, size_t alignment, size_t size)
+{
+ int rc;
+
+ if (((alignment & (alignment - 1)) != 0) ||
+ (alignment < sizeof(void*))) {
+ rc = -EINVAL;
+ } else {
+ rc = byte_pool_alloc_aligned(_malloc_byte_pool, memptr, size,
+ floor_log2(alignment));
+ if (!rc && (*memptr == 0)) {
+ rc = -ENOMEM;
+ }
+ }
+ if (rc && memptr) {
+ *memptr = 0;
+ }
+ return rc;
+}
+
+
+/// Print a dump of a byte pool, including the header and allocation report
+///
+/// \param stream The stream to receive the dump
+///
+/// \param pool The BytePool object to dump
+///
+/// \bug This routine is not thread safe.
+
+void
+byte_pool_report(FILE* stream, BytePool* pool)
+{
+ ByteBlock* block;
+ uint8_t* p8;
+ uint32_t* p32;
+ int i;
+
+ fprintf(stream, ">>> Byte Pool Report for Pool %p <<<\n", pool);
+
+ fprintf(stream, ">>> BytePool Object Dump <<<\n");
+
+#define DUMPIT(x, fmt) \
+ fprintf(stream, "%20s : " #fmt "\n", #x, pool->x)
+
+ DUMPIT(first_row, %d);
+ DUMPIT(last_row, %d);
+ DUMPIT(columns, %d);
+ DUMPIT(log2_columns, %d);
+ DUMPIT(column_mask, 0x%08x);
+ DUMPIT(minimum_block_size, %d);
+ DUMPIT(free, %p);
+ DUMPIT(column_status, %p);
+ DUMPIT(row_status, %lu);
+ DUMPIT(first_block, %p);
+ DUMPIT(big_block, %p);
+ DUMPIT(last_block, %p);
+ DUMPIT(initial_allocation, %d);
+ DUMPIT(bytes_allocated, %d);
+ DUMPIT(bytes_free, %d);
+ DUMPIT(blocks_allocated, %d);
+ DUMPIT(blocks_free, %d);
+ DUMPIT(alloc_calls, %d);
+ DUMPIT(free_calls, %d);
+
+ fprintf(stream, ">>> Byte Pool Allocation Report <<<\n");
+ fprintf(stream,
+ ">>> status : address : size : binary[0:7] : ASCII[0:7] <<<\n");
+
+ for (block = pool->first_block->next;
+ block != pool->last_block;
+ block = block->next) {
+
+ fprintf(stream, " %c : %p : %6zu : ",
+ (block_is_free(block) ? 'F' : 'A'),
+ block, block_size(block));
+
+ p8 = (uint8_t*)((unsigned long)block + sizeof(ByteBlock));
+ p32 = (uint32_t*)p8;
+
+ fprintf(stream, "0x%08x 0x%08x : ", p32[0], p32[1]);
+ for (i = 0; i < 8; i++) {
+ if (isprint(p8[i])) {
+ fputc(p8[i], stream);
+ } else {
+ fputc('.', stream);
+ }
+ }
+ fputc('\n', stream);
+ }
+
+ fprintf(stream, ">>> End Report <<<\n");
+}
diff --git a/src/lib/ppc405lib/byte_pool.h b/src/lib/ppc405lib/byte_pool.h
new file mode 100644
index 0000000..8766745
--- /dev/null
+++ b/src/lib/ppc405lib/byte_pool.h
@@ -0,0 +1,166 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/byte_pool.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __BYTE_POOL_H__
+#define __BYTE_POOL_H__
+
+// $Id$
+
+#ifndef __ASSEMBLER__
+
+#include "ssx_io.h"
+
+struct ByteBlock;
+struct FreeByteBlock;
+
+// A handy constant
+
+#define BITS_PER_UNSIGNED_LONG (8 * sizeof(unsigned long))
+
+
+/// A control structure for a byte pool. The application will never modify the
+/// structure fields directly, but some applications may be interested in
+/// reading the statistics.
+
+typedef struct {
+
+ // The index of the first allocated row of free list pointers
+ int first_row;
+
+ // The index of the last allocated row of free list pointers
+ int last_row;
+
+ // The number of columns in each row of free list pointers
+ int columns;
+
+ // The log2 of the number of columns in each row of free list pointers
+ int log2_columns;
+
+ // The shifted block size is ANDed with this mask to extract the column
+ // number.
+ size_t column_mask;
+
+ // The minimum block size.
+ int minimum_block_size;
+
+ // The vectors of free list pointers
+ struct FreeByteBlock **free[BITS_PER_UNSIGNED_LONG];
+
+ // The array of column status bit masks
+ unsigned long column_status[BITS_PER_UNSIGNED_LONG];
+
+ // The row status bit mask
+ unsigned long row_status;
+
+ // A sentinel node - the first allocated block. Kept for error checking
+ // purposes.
+ struct ByteBlock *first_block;
+
+ // The initial memory allocation. Kept here only for debugging purposes.
+ struct ByteBlock *big_block;
+
+ // A sentinel node - the last allocated block. Kept here for error
+ // checking purposes.
+ struct ByteBlock *last_block;
+
+ // The initial allocation. Kept here for debugging and statistics.
+ size_t initial_allocation;
+
+ // The total number of bytes currently allocated (excludes overhead)
+ size_t bytes_allocated;
+
+ // The total number of bytes currently free in the pool
+ size_t bytes_free;
+
+ // The total number of blocks allocated from the pool
+ size_t blocks_allocated;
+
+ // The total number of blocks free in the pool
+ size_t blocks_free;
+
+ // The number of calls to allocate memory
+ size_t alloc_calls;
+
+ // The number of calls to free memory
+ size_t free_calls;
+
+} BytePool;
+
+extern BytePool *_malloc_byte_pool;
+
+int
+byte_pool_create(BytePool *pool, void *memory, size_t size);
+
+int
+byte_pool_create_tuned(BytePool *pool, void *memory, size_t size,
+ int columns);
+
+int
+byte_pool_alloc(BytePool *pool, void **memory, size_t size);
+
+int
+byte_pool_calloc(BytePool *pool, void **memory, size_t nmemb, size_t size);
+
+int
+byte_pool_free(BytePool *pool, void *memory);
+
+void
+byte_pool_block_info(void* memory,
+ void** actual_address, size_t* actual_size,
+ size_t* useful_size);
+
+int
+byte_pool_alloc_aligned(BytePool *pool, void **memory, size_t size,
+ int alignment);
+
+void *
+malloc(size_t size);
+
+void *
+calloc(size_t nmemb, size_t size);
+
+void
+free(void *ptr);
+
+int
+posix_memalign(void** memptr, size_t alignment, size_t size);
+
+void
+byte_pool_report(FILE* stream, BytePool* pool);
+
+#endif /* __ASSEMBLER__ */
+
+
+// Error/panic codes
+
+#define BYTE_POOL_INVALID_OBJECT 0x00b98e01
+#define BYTE_POOL_INVALID_ARGUMENT 0x00b98e02
+#define BYTE_POOL_REVERSE_LINKAGE 0x00b98e03
+#define BYTE_POOL_FORWARD_LINKAGE 0x00b98e04
+#define BYTE_POOL_NO_MEMORY 0x00b98e05
+
+#define BYTE_POOL_NULL_FREE_LIST 0x00b98e10
+#define BYTE_POOL_INVALID_FREE_LIST 0x00b98e11
+
+#endif /* __BYTE_POOL_H__ */
diff --git a/src/lib/ppc405lib/chip_config.h b/src/lib/ppc405lib/chip_config.h
new file mode 100644
index 0000000..cc772e2
--- /dev/null
+++ b/src/lib/ppc405lib/chip_config.h
@@ -0,0 +1,109 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/chip_config.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __CHIP_CONFIG_H__
+#define __CHIP_CONFIG_H__
+
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2014
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file chip_config.h
+/// \brief Chip configuration data structures for OCC procedures
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+/// A bitmask defining a chip configuration
+///
+/// Since we are using the conventional big-endian notation, any use of these
+/// bitmasks requires that the data being tested is of this type - otherwise
+/// the masks won't work.
+///
+/// Layout:
+///
+/// Bits 0:15 - Core chiplet 0..15 is configured
+/// Bits 16:23 - MCS 0..7 is configured
+/// Bits 24:31 - Centaur 0..7 is configured
+
+typedef uint64_t ChipConfig;
+typedef uint16_t ChipConfigCores;
+typedef uint8_t ChipConfigMcs;
+typedef uint8_t ChipConfigCentaur;
+
+
+/// Convert a ChipConfig into a mask suitable for use as the 32-bit chiplet
+/// mask argument of a PORE wakeup program.
+#if 0
+static inline uint32_t
+pore_exe_mask(ChipConfig config)
+{
+ return (uint32_t)((config >> 32) & 0xffff0000);
+}
+#endif
+
+/// Left justify and mask core chiplet configuration into a uint32_t
+
+static inline uint32_t
+left_justify_core_config(ChipConfig config)
+{
+ return (uint32_t)((config >> 32) & 0xffff0000);
+}
+
+/// Left justify and mask MCS configuration into a uint32_t
+
+static inline uint32_t
+left_justify_mcs_config(ChipConfig config)
+{
+ return (uint32_t)((config >> 16) & 0xff000000);
+}
+
+/// Left justify and mask Centaur configuration into a uint32_t
+
+static inline uint32_t
+left_justify_centaur_config(ChipConfig config)
+{
+ return (uint32_t)((config >> 8) & 0xff000000);
+}
+
+#endif // __ASSEMBLER__
+
+
+#define CHIP_CONFIG_CORE_BASE 0
+#define CHIP_CONFIG_CORE(n) \
+ ((0x8000000000000000ull >> CHIP_CONFIG_CORE_BASE) >> (n))
+
+#define CHIP_CONFIG_MCS_BASE 16
+#define CHIP_CONFIG_MCS(n) \
+ ((0x8000000000000000ull >> CHIP_CONFIG_MCS_BASE) >> (n))
+
+#define CHIP_CONFIG_CENTAUR_BASE 24
+#define CHIP_CONFIG_CENTAUR(n) \
+ ((0x8000000000000000ull >> CHIP_CONFIG_CENTAUR_BASE) >> (n))
+
+
+#endif /* __CHIP_CONFIG_H__ */
diff --git a/src/lib/ppc405lib/ctype.c b/src/lib/ppc405lib/ctype.c
new file mode 100644
index 0000000..5069590
--- /dev/null
+++ b/src/lib/ppc405lib/ctype.c
@@ -0,0 +1,46 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/ctype.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: ctype.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/ctype.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ctype.c
+/// \brief Replacement for <ctype.h> functions
+///
+/// This file contains entry point equivalents for the "ctype.h" macros.
+/// These would only ever be used by assembler programs, therefore it's likely
+/// that the object file will never be linked into an image.
+
+#define __CTYPE_C__
+#include "ctype.h"
+#undef __CTYPE_C__
+
+
+
+
diff --git a/src/lib/ppc405lib/ctype.h b/src/lib/ppc405lib/ctype.h
new file mode 100644
index 0000000..9e41e45
--- /dev/null
+++ b/src/lib/ppc405lib/ctype.h
@@ -0,0 +1,149 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/ctype.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __CTYPE_H__
+#define __CTYPE_H__
+
+// $Id: ctype.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/ctype.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ctype.h
+/// \brief Replacement for <ctype.h>
+///
+/// The Gnu <ctype.h> requires some locale information to be defined. We
+/// avoid this overhead and implement the simple functions, simply assuming
+/// standard 8-bit ASCII. The standard requires that these be defined as entry
+/// points, but may be defined as macros, therefore all macros defined by
+/// ctype.h are also be replicated in \c ctype.c
+
+// The reference for which characters are included in each set was:
+//
+// http://www.cplusplus.com/reference/clibrary/cctype/
+//
+// Note that no code was copied from the above or any other published
+// description of the ctype.h functionality.
+
+// To keep space to a minimum we encode the 8 common types directly into
+// an 8-bit mask. Other types take a little longer to compute.
+
+#define _CTYPE_CNTRL 0x01
+#define _CTYPE_SPACE 0x02
+#define _CTYPE_PRINT 0x04
+#define _CTYPE_PUNCT 0x08
+#define _CTYPE_UPPER 0x10
+#define _CTYPE_LOWER 0x20
+#define _CTYPE_DIGIT 0x40
+#define _CTYPE_XDIGIT 0x80
+
+#ifndef __ASSEMBLER__
+
+#include "stdint.h"
+
+/// \bug <ctype.h> can not include <stdio.h> to get the definition of
+/// EOF. This is because it causes conflicts withe the pore_inline* code which
+/// is portable (and ported) to Linux and PHYP. We need to go back through the
+/// way the includes are done in SSX and this library and fix this. We should
+/// have redefined <stdio.h> rather than creating a new "ssx_io.h"
+
+#define _CTYPE_EOF -1
+
+// Note that in all of the type macros, 'c' is an unsigned char.
+
+extern const uint8_t _ctype[256];
+
+#define _CTYPE_ISLOWER(c) (_ctype[c] & _CTYPE_LOWER)
+
+#define _CTYPE_ISUPPER(c) (_ctype[c] & _CTYPE_UPPER)
+
+#define _CTYPE_ISALPHA(c) (_CTYPE_ISUPPER(c) || _CTYPE_ISLOWER(c))
+
+#define _CTYPE_ISDIGIT(c) (_ctype[c] & _CTYPE_DIGIT)
+
+#define _CTYPE_ISALNUM(c) (_CTYPE_ISALPHA(c) || _CTYPE_ISDIGIT(c))
+
+#define _CTYPE_ISXDIGIT(c) (_ctype[c] & _CTYPE_XDIGIT)
+
+#define _CTYPE_ISCNTRL(c) (_ctype[c] & _CTYPE_CNTRL)
+
+#define _CTYPE_ISSPACE(c) (_ctype[c] & _CTYPE_SPACE)
+
+#define _CTYPE_ISPRINT(c) (_ctype[c] & _CTYPE_PRINT)
+
+#define _CTYPE_ISGRAPH(c) (_CTYPE_ISPRINT(c) && ((c) != 0x20))
+
+#define _CTYPE_ISPUNCT(c) (_ctype[c] & _CTYPE_PUNCT)
+
+#define _CTYPE_TOUPPER(c) (islower(c) ? ((c) + ('A' - 'a')) : (c))
+
+#define _CTYPE_TOLOWER(c) (isupper(c) ? ((c) - ('A' - 'a')) : (c))
+
+// When #include'ed into ctype.c, the non-inline forms of the functions are
+// created.
+//
+// Note that the specification requires that 'c' "must have the value of an
+// unsigned char or EOF". The specification also stipulates that "The values
+// returned are non-zero if the character c falls into the tested class, and a
+// zero value if not."
+
+#ifdef __CTYPE_C__
+#define _CTYPE_EXTERN_INLINE
+#else
+#define _CTYPE_EXTERN_INLINE extern inline
+#endif
+
+#define _CTYPE_PREDICATE(predicate, def) \
+ _CTYPE_EXTERN_INLINE int predicate(int c) { \
+ return ((c == _CTYPE_EOF) ? \
+ 0 : _CTYPE_##def((unsigned char)c)); \
+ }
+
+#define _CTYPE_FUNCTION(function, def) \
+ _CTYPE_EXTERN_INLINE int function(int c) { \
+ return ((c == _CTYPE_EOF) ? \
+ _CTYPE_EOF : _CTYPE_##def((unsigned char)c)); \
+ }
+
+_CTYPE_PREDICATE(islower, ISLOWER)
+_CTYPE_PREDICATE(isupper, ISUPPER)
+_CTYPE_PREDICATE(isalpha, ISALPHA)
+_CTYPE_PREDICATE(isdigit, ISDIGIT)
+_CTYPE_PREDICATE(isalnum, ISALNUM)
+_CTYPE_PREDICATE(isxdigit, ISXDIGIT)
+_CTYPE_PREDICATE(iscntrl, ISCNTRL)
+_CTYPE_PREDICATE(isspace, ISSPACE)
+_CTYPE_PREDICATE(isprint, ISPRINT)
+_CTYPE_PREDICATE(isgraph, ISGRAPH)
+_CTYPE_PREDICATE(ispunct, ISPUNCT)
+
+_CTYPE_FUNCTION(tolower, TOLOWER)
+_CTYPE_FUNCTION(toupper, TOUPPER)
+
+#endif // __ASSEMBLER__
+
+#endif /* __CTYPE_H__ */
diff --git a/src/lib/ppc405lib/ctype_table.c b/src/lib/ppc405lib/ctype_table.c
new file mode 100644
index 0000000..01dd08a
--- /dev/null
+++ b/src/lib/ppc405lib/ctype_table.c
@@ -0,0 +1,302 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/ctype_table.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: ctype_table.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/ctype_table.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ctype_table.c
+/// \brief Character table for <ctype.h> functions.
+///
+/// This table is used by the <ctype.h> functions for a quick lookup of
+/// character type information. Because the true functional forms of <ctype.h>
+/// functions are likely never required, but this file is always required, it
+/// is stored separately from ctype.c to (slightly) reduce code/data space
+/// requirements.
+
+#include <stdint.h>
+#include <ctype.h>
+
+const uint8_t _ctype[256] = {
+ _CTYPE_CNTRL, /* 0 00 NUL Null char */
+ _CTYPE_CNTRL, /* 1 01 SOH Start of Heading */
+ _CTYPE_CNTRL, /* 2 02 STX Start of Text */
+ _CTYPE_CNTRL, /* 3 03 ETX End of Text */
+ _CTYPE_CNTRL, /* 4 04 EOT End of Transmission */
+ _CTYPE_CNTRL, /* 5 05 ENQ Enquiry */
+ _CTYPE_CNTRL, /* 6 06 ACK Acknowledgment */
+ _CTYPE_CNTRL, /* 7 07 BEL Bell */
+ _CTYPE_CNTRL, /* 8 08 BS Back Space */
+ _CTYPE_CNTRL | _CTYPE_SPACE, /* 9 09 HT Horizontal Tab */
+ _CTYPE_CNTRL | _CTYPE_SPACE, /* 10 0A LF Line Feed */
+ _CTYPE_CNTRL | _CTYPE_SPACE, /* 11 0B VT Vertical Tab */
+ _CTYPE_CNTRL | _CTYPE_SPACE, /* 12 0C FF Form Feed */
+ _CTYPE_CNTRL | _CTYPE_SPACE, /* 13 0D CR Carriage Return */
+ _CTYPE_CNTRL, /* 14 0E SO Shift Out / X-On */
+ _CTYPE_CNTRL, /* 15 0F SI Shift In / X-Off */
+ 0, /* 16 10 DLE Data Line Escape */
+ 0, /* 17 11 DC1 Device Control 1 (oft. XON) */
+ 0, /* 18 12 DC2 Device Control 2 */
+ 0, /* 19 13 DC3 Device Control 3 (oft. XOFF) */
+ 0, /* 20 14 DC4 Device Control 4 */
+ 0, /* 21 15 NAK Negative Acknowledgement */
+ 0, /* 22 16 SYN Synchronous Idle */
+ 0, /* 23 17 ETB End of Transmit Block */
+ 0, /* 24 18 CAN Cancel */
+ 0, /* 25 19 EM End of Medium */
+ 0, /* 26 1A SUB Substitute */
+ 0, /* 27 1B ESC Escape */
+ 0, /* 28 1C FS File Separator */
+ 0, /* 29 1D GS Group Separator */
+ 0, /* 30 1E RS Record Separator */
+ 0, /* 31 1F US Unit Separator */
+ _CTYPE_PRINT | _CTYPE_SPACE, /* 32 20 Space */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 33 21 ! Exclamation mark */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 34 22 " Double quotes (or speech marks) */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 35 23 # Number */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 36 24 $ Dollar */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 37 25 % Procenttecken */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 38 26 & Ampersand */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 39 27 ' Single quote */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 40 28 ( Open parenthesis (or open bracket) */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 41 29 ) Close parenthesis (or close bracket) */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 42 2A * Asterisk */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 43 2B + Plus */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 44 2C , Comma */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 45 2D - Hyphen */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 46 2E . Period, dot or full stop */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 47 2F / Slash or divide */
+ _CTYPE_PRINT | _CTYPE_DIGIT, /* 48 30 0 Zero */
+ _CTYPE_PRINT | _CTYPE_DIGIT, /* 49 31 1 One */
+ _CTYPE_PRINT | _CTYPE_DIGIT, /* 50 32 2 Two */
+ _CTYPE_PRINT | _CTYPE_DIGIT, /* 51 33 3 Three */
+ _CTYPE_PRINT | _CTYPE_DIGIT, /* 52 34 4 Four */
+ _CTYPE_PRINT | _CTYPE_DIGIT, /* 53 35 5 Five */
+ _CTYPE_PRINT | _CTYPE_DIGIT, /* 54 36 6 Six */
+ _CTYPE_PRINT | _CTYPE_DIGIT, /* 55 37 7 Seven */
+ _CTYPE_PRINT | _CTYPE_DIGIT, /* 56 38 8 Eight */
+ _CTYPE_PRINT | _CTYPE_DIGIT, /* 57 39 9 Nine */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 58 3A : Colon */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 59 3B ; Semicolon */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 60 3C < Less than (or open angled bracket) */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 61 3D = Equals */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 62 3E > Greater than (or close angled bracket) */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 63 3F ? Question mark */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 64 40 @ At symbol */
+ _CTYPE_PRINT | _CTYPE_UPPER | _CTYPE_XDIGIT, /* 65 41 A Uppercase A */
+ _CTYPE_PRINT | _CTYPE_UPPER | _CTYPE_XDIGIT, /* 66 42 B Uppercase B */
+ _CTYPE_PRINT | _CTYPE_UPPER | _CTYPE_XDIGIT, /* 67 43 C Uppercase C */
+ _CTYPE_PRINT | _CTYPE_UPPER | _CTYPE_XDIGIT, /* 68 44 D Uppercase D */
+ _CTYPE_PRINT | _CTYPE_UPPER | _CTYPE_XDIGIT, /* 69 45 E Uppercase E */
+ _CTYPE_PRINT | _CTYPE_UPPER | _CTYPE_XDIGIT, /* 70 46 F Uppercase F */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 71 47 G Uppercase G */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 72 48 H Uppercase H */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 73 49 I Uppercase I */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 74 4A J Uppercase J */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 75 4B K Uppercase K */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 76 4C L Uppercase L */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 77 4D M Uppercase M */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 78 4E N Uppercase N */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 79 4F O Uppercase O */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 80 50 P Uppercase P */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 81 51 Q Uppercase Q */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 82 52 R Uppercase R */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 83 53 S Uppercase S */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 84 54 T Uppercase T */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 85 55 U Uppercase U */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 86 56 V Uppercase V */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 87 57 W Uppercase W */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 88 58 X Uppercase X */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 89 59 Y Uppercase Y */
+ _CTYPE_PRINT | _CTYPE_UPPER, /* 90 5A Z Uppercase Z */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 91 5B [ Opening bracket */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 92 5C \ Backslash */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 93 5D ] Closing bracket */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 94 5E ^ Caret - circumflex */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 95 5F _ Underscore */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 96 60 ` Grave accent */
+ _CTYPE_PRINT | _CTYPE_LOWER | _CTYPE_XDIGIT, /* 97 61 a Lowercase a */
+ _CTYPE_PRINT | _CTYPE_LOWER | _CTYPE_XDIGIT, /* 98 62 b Lowercase b */
+ _CTYPE_PRINT | _CTYPE_LOWER | _CTYPE_XDIGIT, /* 99 63 c Lowercase c */
+ _CTYPE_PRINT | _CTYPE_LOWER | _CTYPE_XDIGIT, /* 100 64 d Lowercase d */
+ _CTYPE_PRINT | _CTYPE_LOWER | _CTYPE_XDIGIT, /* 101 65 e Lowercase e */
+ _CTYPE_PRINT | _CTYPE_LOWER | _CTYPE_XDIGIT, /* 102 66 f Lowercase f */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 103 67 g Lowercase g */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 104 68 h Lowercase h */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 105 69 i Lowercase i */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 106 6A j Lowercase j */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 107 6B k Lowercase k */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 108 6C l Lowercase l */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 109 6D m Lowercase m */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 110 6E n Lowercase n */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 111 6F o Lowercase o */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 112 70 p Lowercase p */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 113 71 q Lowercase q */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 114 72 r Lowercase r */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 115 73 s Lowercase s */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 116 74 t Lowercase t */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 117 75 u Lowercase u */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 118 76 v Lowercase v */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 119 77 w Lowercase w */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 120 78 x Lowercase x */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 121 79 y Lowercase y */
+ _CTYPE_PRINT | _CTYPE_LOWER, /* 122 7A z Lowercase z */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 123 7B { Opening brace */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 124 7C | Vertical bar */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 125 7D } Closing brace */
+ _CTYPE_PRINT | _CTYPE_PUNCT, /* 126 7E ~ Equivalency sign - tilde */
+ 0, /* 127 7F Delete */
+ 0, /* 128 80 Euro sign */
+ 0, /* 129 81 */
+ 0, /* 130 82 ' Single low-9 quotation mark */
+ 0, /* 131 83 Latin small letter f with hook */
+ 0, /* 132 84 " Double low-9 quotation mark */
+ 0, /* 133 85 Horizontal ellipsis */
+ 0, /* 134 86 Dagger */
+ 0, /* 135 87 Double dagger */
+ 0, /* 136 88 Modifier letter circumflex accent */
+ 0, /* 137 89 Per mille sign */
+ 0, /* 138 8A Latin capital letter S with caron */
+ 0, /* 139 8B Single left-pointing angle quotation */
+ 0, /* 140 8C Latin capital ligature OE */
+ 0, /* 141 8D */
+ 0, /* 142 8E Latin captial letter Z with caron */
+ 0, /* 143 8F */
+ 0, /* 144 90 */
+ 0, /* 145 91 ' Left single quotation mark */
+ 0, /* 146 92 ' Right single quotation mark */
+ 0, /* 147 93 " Left double quotation mark */
+ 0, /* 148 94 " Right double quotation mark */
+ 0, /* 149 95 Bullet */
+ 0, /* 150 96 En dash */
+ 0, /* 151 97 Em dash */
+ 0, /* 152 98 Small tilde */
+ 0, /* 153 99 Trade mark sign */
+ 0, /* 154 9A Latin small letter S with caron */
+ 0, /* 155 9B Single right-pointing angle quotation mark */
+ 0, /* 156 9C Latin small ligature oe */
+ 0, /* 157 9D */
+ 0, /* 158 9E Latin small letter z with caron */
+ 0, /* 159 9F Latin capital letter Y with diaeresis */
+ 0, /* 160 A0 Non-breaking space */
+ 0, /* 161 A1 Inverted exclamation mark */
+ 0, /* 162 A2 Cent sign */
+ 0, /* 163 A3 Pound sign */
+ 0, /* 164 A4 Currency sign */
+ 0, /* 165 A5 Yen sign */
+ 0, /* 166 A6 Pipe, Broken vertical bar */
+ 0, /* 167 A7 Section sign */
+ 0, /* 168 A8 Spacing diaeresis - umlaut */
+ 0, /* 169 A9 Copyright sign */
+ 0, /* 170 AA Feminine ordinal indicator */
+ 0, /* 171 AB Left double angle quotes */
+ 0, /* 172 AC Not sign */
+ 0, /* 173 AD Soft hyphen */
+ 0, /* 174 AE Registered trade mark sign */
+ 0, /* 175 AF Spacing macron - overline */
+ 0, /* 176 B0 Degree sign */
+ 0, /* 177 B1 Plus-or-minus sign */
+ 0, /* 178 B2 Superscript two - squared */
+ 0, /* 179 B3 Superscript three - cubed */
+ 0, /* 180 B4 Acute accent - spacing acute */
+ 0, /* 181 B5 Micro sign */
+ 0, /* 182 B6 Pilcrow sign - paragraph sign */
+ 0, /* 183 B7 Middle dot - Georgian comma */
+ 0, /* 184 B8 Spacing cedilla */
+ 0, /* 185 B9 Superscript one */
+ 0, /* 186 BA Masculine ordinal indicator */
+ 0, /* 187 BB Right double angle quotes */
+ 0, /* 188 BC one quarter */
+ 0, /* 189 BD Fraction one half */
+ 0, /* 190 BE Fraction three quarters */
+ 0, /* 191 BF Inverted question mark */
+ 0, /* 192 C0 Latin capital letter A with grave */
+ 0, /* 193 C1 Latin capital letter A with acute */
+ 0, /* 194 C2 Latin capital letter A with circumflex */
+ 0, /* 195 C3 Latin capital letter A with tilde */
+ 0, /* 196 C4 Latin capital letter A with diaeresis */
+ 0, /* 197 C5 Latin capital letter A with ring above */
+ 0, /* 198 C6 Latin capital letter AE */
+ 0, /* 199 C7 Latin capital letter C with cedilla */
+ 0, /* 200 C8 Latin capital letter E with grave */
+ 0, /* 201 C9 Latin capital letter E with acute */
+ 0, /* 202 CA Latin capital letter E with circumflex */
+ 0, /* 203 CB Latin capital letter E with diaeresis */
+ 0, /* 204 CC Latin capital letter I with grave */
+ 0, /* 205 CD Latin capital letter I with acute */
+ 0, /* 206 CE Latin capital letter I with circumflex */
+ 0, /* 207 CF Latin capital letter I with diaeresis */
+ 0, /* 208 D0 Latin capital letter ETH */
+ 0, /* 209 D1 Latin capital letter N with tilde */
+ 0, /* 210 D2 Latin capital letter O with grave */
+ 0, /* 211 D3 Latin capital letter O with acute */
+ 0, /* 212 D4 Latin capital letter O with circumflex */
+ 0, /* 213 D5 Latin capital letter O with tilde */
+ 0, /* 214 D6 Latin capital letter O with diaeresis */
+ 0, /* 215 D7 Multiplication sign */
+ 0, /* 216 D8 Latin capital letter O with slash */
+ 0, /* 217 D9 Latin capital letter U with grave */
+ 0, /* 218 DA Latin capital letter U with acute */
+ 0, /* 219 DB Latin capital letter U with circumflex */
+ 0, /* 220 DC Latin capital letter U with diaeresis */
+ 0, /* 221 DD Latin capital letter Y with acute */
+ 0, /* 222 DE Latin capital letter THORN */
+ 0, /* 223 DF Latin small letter sharp s - ess-zed */
+ 0, /* 224 E0 Latin small letter a with grave */
+ 0, /* 225 E1 Latin small letter a with acute */
+ 0, /* 226 E2 Latin small letter a with circumflex */
+ 0, /* 227 E3 Latin small letter a with tilde */
+ 0, /* 228 E4 Latin small letter a with diaeresis */
+ 0, /* 229 E5 Latin small letter a with ring above */
+ 0, /* 230 E6 Latin small letter ae */
+ 0, /* 231 E7 Latin small letter c with cedilla */
+ 0, /* 232 E8 Latin small letter e with grave */
+ 0, /* 233 E9 Latin small letter e with acute */
+ 0, /* 234 EA Latin small letter e with circumflex */
+ 0, /* 235 EB Latin small letter e with diaeresis */
+ 0, /* 236 EC Latin small letter i with grave */
+ 0, /* 237 ED Latin small letter i with acute */
+ 0, /* 238 EE Latin small letter i with circumflex */
+ 0, /* 239 EF Latin small letter i with diaeresis */
+ 0, /* 240 F0 Latin small letter eth */
+ 0, /* 241 F1 Latin small letter n with tilde */
+ 0, /* 242 F2 Latin small letter o with grave */
+ 0, /* 243 F3 Latin small letter o with acute */
+ 0, /* 244 F4 Latin small letter o with circumflex */
+ 0, /* 245 F5 Latin small letter o with tilde */
+ 0, /* 246 F6 Latin small letter o with diaeresis */
+ 0, /* 247 F7 Division sign */
+ 0, /* 248 F8 Latin small letter o with slash */
+ 0, /* 249 F9 Latin small letter u with grave */
+ 0, /* 250 FA Latin small letter u with acute */
+ 0, /* 251 FB Latin small letter u with circumflex */
+ 0, /* 252 FC Latin small letter u with diaeresis */
+ 0, /* 253 FD Latin small letter y with acute */
+ 0, /* 254 FE Latin small letter thorn */
+ 0, /* 255 FF Latin small letter y with diaeresis */
+};
diff --git a/src/lib/ppc405lib/errno.h b/src/lib/ppc405lib/errno.h
new file mode 100644
index 0000000..e5ac6a9
--- /dev/null
+++ b/src/lib/ppc405lib/errno.h
@@ -0,0 +1,49 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/errno.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __ERRNO_H__
+#define __ERRNO_H__
+
+// $Id: errno.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/errno.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file errno.h
+/// \brief Replacement for <errno.h>
+///
+/// SSX does not support a per-thread or global 'errno'. The standard Unix
+/// errno values returned by library functions are defined here. The prefix
+/// code is the 'telephone code' for "errn".
+
+#define EINVAL 0x00377601
+#define EBADF 0x00377602
+#define EAGAIN 0x00377603
+#define ENXIO 0x00377604
+#define ENOMEM 0x00377605
+
+#endif /* __ERRNO_H__ */
diff --git a/src/lib/ppc405lib/fgetc.c b/src/lib/ppc405lib/fgetc.c
new file mode 100644
index 0000000..6e6a1f9
--- /dev/null
+++ b/src/lib/ppc405lib/fgetc.c
@@ -0,0 +1,112 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/fgetc.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: fgetc.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/fgetc.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file fgetc.c
+/// \brief Implementation of fgetc() and ungetc()
+///
+/// The implementations of these APIs are split out to save code space for
+/// applications that do not require them.
+
+#include "ssx_io.h"
+
+
+/// Read a character from a stream
+///
+/// fgetc() reads the next character from \a stream and returns it as an
+/// unsigned char cast to an int, or EOF on end of file or error.
+
+int
+fgetc(FILE* stream)
+{
+ unsigned char c;
+ size_t read;
+ int rc;
+
+ if (stream->flags & SSX_FILE_HAS_CHARACTER) {
+ stream->flags &= ~SSX_FILE_HAS_CHARACTER;
+ rc = stream->character;
+ } else {
+ rc = sread(stream, &c, 1, &read);
+ if (rc || (read != 1)) {
+ rc = EOF;
+ } else {
+ rc = c;
+ if (c == '\n') {
+ stream->lines++;
+ }
+ }
+ }
+ return rc;
+}
+
+
+/// Push a character back onto a stream
+///
+/// ungetc() pushes \a c back to \a stream, cast to unsigned char, where it is
+/// available for subsequent fgetc() operations. Only one pushback is
+/// implemented. A call of ungetc() on a stream that already has a character
+/// pushed back will drop the new push-back and return EOF. Otherwise
+/// ungetc() returns \a c.
+
+int
+ungetc(int c, FILE* stream)
+{
+ int rc;
+
+ if (stream->flags & SSX_FILE_HAS_CHARACTER) {
+ rc = EOF;
+ } else {
+ stream->flags |= SSX_FILE_HAS_CHARACTER;
+ stream->character = c;
+ rc = c;
+ }
+ return rc;
+}
+
+/// Return the number of newline characters read from a stream
+///
+/// This API is an SSX entension to the \<stdio\> APIs. It returns the number
+/// of newline characters read from the stream using fgetc(). Newline
+/// characters read via direct calls to sread() in the stream are not counted.
+///
+/// An application that sees an error while reading from a stream can print
+/// flines() or flines() + 1 (depending on the application) to help users
+/// track down errors in their input.
+size_t
+flines(FILE* stream)
+{
+ return stream->lines;
+}
+
+
+
+
diff --git a/src/lib/ppc405lib/initcall.c b/src/lib/ppc405lib/initcall.c
new file mode 100644
index 0000000..664fb6e
--- /dev/null
+++ b/src/lib/ppc405lib/initcall.c
@@ -0,0 +1,70 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/initcall.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id$
+
+/// \file initcall.c
+/// \brief An anonymous early initialization facility for SSX applications
+
+#include "ssx.h"
+#include "initcall.h"
+
+// These linker symbols must be defined if the initcall facility is used. The
+// special ELF section .data.initcall contains an array of Initcall structures
+// for all declared initcalls.
+
+extern InitCall _INITCALL_SECTION_BASE[];
+extern SsxLinkerSymbol _INITCALL_SECTION_SIZE;
+
+void
+_initcall_run(InitCall* initcall)
+{
+ void (*f)(void* arg);
+
+ f = initcall->initcall;
+ if (f) {
+ initcall->initcall = 0;
+ f(initcall->arg);
+ }
+}
+
+
+void
+initcall_run_all()
+{
+ InitCall* initcall;
+ size_t nCalls;
+
+ initcall = _INITCALL_SECTION_BASE;
+ nCalls = (size_t)(&_INITCALL_SECTION_SIZE) / sizeof(InitCall);
+
+ for (; nCalls--; initcall++) {
+ _initcall_run(initcall);
+ }
+}
+
+
+
+
+
diff --git a/src/lib/ppc405lib/initcall.h b/src/lib/ppc405lib/initcall.h
new file mode 100644
index 0000000..af8b53c
--- /dev/null
+++ b/src/lib/ppc405lib/initcall.h
@@ -0,0 +1,116 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/initcall.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __INITCALL_H__
+#define __INITCALL_H__
+
+// $Id$
+
+/// \file initcall.h
+/// \brief An early initialization facility for SSX applications
+///
+/// The C language standard does not define a generic load-time initialization
+/// method, unlike C++ which supports load-time initialization of static
+/// objects. The \e initcall facility implements a simple method for SSX
+/// applications to declare early initialization functions that are executed
+/// prior to or during the invocation of main().
+///
+/// An \e initcall can be any function with the prototype
+///
+/// \code
+///
+/// void (*initcall)(void* arg)
+///
+/// \endcode
+///
+/// Initcalls are declared with the INITCALL() macro. An initcall is
+/// represented by a named structure, and typically an initcall will be
+/// declared static to the compilation unit that implements the initcall:
+///
+/// \code
+///
+/// void (*init_fn)(void* arg);
+/// void* init_data = ...;
+/// static INITCALL(init_var, init_fn, init_data);
+///
+/// \endcode
+///
+/// All INITCALLS loaded in the executable image are executed by the
+/// initcall_run_all() API. An SSX application will typically call
+/// initcall_run_all() in the function declared as the \a ssx_main_hook, or in
+/// the main() routine itself.
+///
+/// Initcalls are run in an arbitrary order. However if initcall \a b is
+/// dependent on initcall \a a, then initcall \a b can execute
+/// initcall_run(&a) to guarantee that initcall \a a runs before \a b.
+/// Regardless, every initcall is run exectly once by the initcall facility,
+/// even if initcall_run() or initcall_run_all() were to be used multiple
+/// times.
+///
+/// Behind the scenes, initcalls are implemented by a special ELF section,
+/// .data.initcall, that records all declared initcalls. The
+/// initcall_run_all() API simply runs all initcalls declared in
+/// .data.initcall.
+
+/// The structure representing an initcall
+
+typedef struct {
+
+ /// The initialization function
+ ///
+ /// Prior to running the initcall, this field is zeroed. This guarantess
+ /// that each initcall is run at most 1 time.
+ void (*initcall)(void* arg);
+
+ /// The argument to the initialization function
+ void* arg;
+
+} InitCall;
+
+
+/// Declare an initcall
+///
+/// This macro generates C code and global data so must be placed at file
+/// scope in a C file, not in a header file or inside a C function
+/// body. Unless the initcall needs to be referenced by another initcall (to
+/// guarantee ordering), this declaration will normally be prepended with
+/// 'static'.
+#define INITCALL(_var, _initcall, _arg) \
+ InitCall _var __attribute__ ((used, section (".data.initcall"))) = \
+ {.initcall = _initcall, .arg = _arg};
+
+
+/// Run the initcall represented by an InitCall structure, assuming it has not
+/// already run.
+///
+/// \param[in] i_initcall The address of the initcall structure to run
+void
+initcall_run(InitCall* i_initcall);
+
+
+/// Run all initcalls
+void
+initcall_run_all();
+
+#endif // __INITCALL_H__
diff --git a/src/lib/ppc405lib/lfsr.c b/src/lib/ppc405lib/lfsr.c
new file mode 100644
index 0000000..21ddb93
--- /dev/null
+++ b/src/lib/ppc405lib/lfsr.c
@@ -0,0 +1,50 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/lfsr.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id$
+
+/// \file lfsr.c
+/// \brief
+
+#include <stdint.h>
+#include "lfsr.h"
+
+// Parity for 4-bit numbers
+static uint8_t S_parity4[16] = {
+ 0, 1, 1, 0,
+ 1, 0, 0, 1,
+ 1, 0, 0, 1,
+ 0, 1, 1, 0
+};
+
+// 64, 63, 61, 60 LFSR. The routine is coded with the uint8_t casting to help
+// the compiler generate more efficient code.
+
+void
+_lfsr64(uint64_t* io_seed)
+{
+ *io_seed = (*io_seed << 1) |
+ S_parity4[(uint8_t)((*io_seed >> 59) & 0x3) |
+ (uint8_t)((*io_seed >> 60) & 0xc)];
+}
diff --git a/src/lib/ppc405lib/lfsr.h b/src/lib/ppc405lib/lfsr.h
new file mode 100644
index 0000000..951ec45
--- /dev/null
+++ b/src/lib/ppc405lib/lfsr.h
@@ -0,0 +1,46 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/lfsr.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __LFSR_H__
+#define __LFSR_H__
+
+/// \file lfsr.h
+/// \brief Linear-Feedback Shift Register Implementations
+///
+/// The 32- and 64-bit pseudo-random number generators in this library are of
+/// the linear-conguential type. These maximal-length LFSR pseudo-random
+/// sequence generators are also provided.
+
+/// 64-bit LFSR
+///
+/// \param[in,out] io_seed The input seed is converted in one step to the
+/// output seed.
+///
+/// This 64-bit LFSR uses taps 64, 63, 61, and 60. In big-endian numbering
+/// these are bits 0, 1, 3 and 4. This LFSR is also implemented for the PORE
+/// engines in the file pore_rand.pS.
+void
+_lfsr64(uint64_t* io_seed);
+
+#endif // __LFSR_H__
diff --git a/src/lib/ppc405lib/libppc405files.mk b/src/lib/ppc405lib/libppc405files.mk
new file mode 100644
index 0000000..59aa7a0
--- /dev/null
+++ b/src/lib/ppc405lib/libppc405files.mk
@@ -0,0 +1,74 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/lib/ppc405lib/libppc405files.mk $
+#
+# OpenPOWER OnChipController Project
+#
+# Contributors Listed Below - COPYRIGHT 2015
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+# IBM_PROLOG_END_TAG
+# @file libppc405files.mk
+#
+# @brief mk for libppc405.a object files
+#
+# @page ChangeLogs Change Logs
+# @section libppc405files.mk
+# @verbatim
+#
+#
+# Change Log ******************************************************************
+# Flag Defect/Feature User Date Description
+# ------ -------------- ---------- ------------ -----------
+#
+# @endverbatim
+#
+##########################################################################
+# INCLUDES
+##########################################################################
+
+C-SOURCES = \
+ assert.c \
+ byte_pool.c \
+ ctype.c \
+ ctype_table.c \
+ fgetc.c \
+ initcall.c \
+ lfsr.c \
+ mutex.c \
+ periodic_semaphore.c \
+ polling.c \
+ printf.c \
+ progress.c \
+ puts.c \
+ rtx_stdio.c \
+ simics_stdio.c \
+ sprintf.c \
+ ssx_dump.c \
+ ssx_io.c \
+ stdlib.c \
+ strcasecmp.c \
+ strdup.c \
+ string.c \
+ string_stream.c \
+ strtox.c \
+ sxlock.c \
+ time.c
+
+S-SOURCES =
+
+LIBPPC405_OBJECTS = $(C-SOURCES:.c=.o) $(S-SOURCES:.S=.o)
diff --git a/src/lib/ppc405lib/libssx.h b/src/lib/ppc405lib/libssx.h
new file mode 100644
index 0000000..601eb00
--- /dev/null
+++ b/src/lib/ppc405lib/libssx.h
@@ -0,0 +1,44 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/libssx.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __LIBSSX_H__
+#define __LIBSSX_H__
+
+// $Id: libssx.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/libssx.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file libssx.h
+/// \brief Header definitions with no other obvious home
+
+// Kernel panics
+
+#define ASSERTION_FAILURE 0x00542701
+#define ERROR_EXIT 0x00542702
+
+#endif // __LIBSSX_H__
diff --git a/src/lib/ppc405lib/mutex.c b/src/lib/ppc405lib/mutex.c
new file mode 100644
index 0000000..db57f54
--- /dev/null
+++ b/src/lib/ppc405lib/mutex.c
@@ -0,0 +1,129 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/mutex.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id$
+
+/// \file mutex.c
+/// \brief A ThreadX-style mutual exclusion object
+
+#include "mutex.h"
+
+int
+mutex_create(Mutex* i_mutex)
+{
+ int rc;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(i_mutex == 0, SSX_INVALID_OBJECT);
+ }
+
+ rc = ssx_semaphore_create(&(i_mutex->sem), 1, 1);
+ i_mutex->thread = 0;
+ i_mutex->count = 0;
+
+ return rc;
+}
+
+
+// If the current thread owns the Mutex we simply increment the count,
+// otherwise pend for the semaphore.
+//
+// Note: It's possible this doesn't need to be done in a critical section. The
+// fact that ssx_semaphore_pend() is atomic may be sufficient since it locks
+// the Mutex.
+
+int
+mutex_pend(Mutex* i_mutex, SsxInterval i_timeout)
+{
+ int rc;
+ SsxMachineContext ctx;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(i_mutex == 0, SSX_INVALID_OBJECT);
+ SSX_ERROR_UNLESS_THREAD_CONTEXT();
+ }
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ if (i_mutex->thread == ssx_current()) {
+
+ i_mutex->count++;
+ if (i_mutex->count == 0) {
+ rc = MUTEX_OVERFLOW;
+ } else {
+ rc = 0;
+ }
+
+ } else {
+
+ rc = ssx_semaphore_pend(&(i_mutex->sem), i_timeout);
+ if (rc == 0) {
+ i_mutex->thread = ssx_current();
+ i_mutex->count = 1;
+ }
+ }
+
+ ssx_critical_section_exit(&ctx);
+
+ return rc;
+}
+
+
+// If the current thread owns the Mutex we decrement the count and free the
+// object when the count goes to 0.
+//
+// Note: It's possible this doesn't need to be done in a critical section. The
+// fact that ssx_semaphore_pend() is atomic may be sufficient since it locks
+// the Mutex.
+
+int
+mutex_post(Mutex* i_mutex)
+{
+ int rc;
+ SsxMachineContext ctx;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(i_mutex == 0, SSX_INVALID_OBJECT);
+ SSX_ERROR_UNLESS_THREAD_CONTEXT();
+ }
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ SSX_ERROR_IF(i_mutex->thread != ssx_current(), MUTEX_NOT_OWNED);
+
+ if (--i_mutex->count == 0) {
+ i_mutex->thread = 0;
+ rc = ssx_semaphore_post(&(i_mutex->sem));
+ } else {
+ rc = 0;
+ }
+
+ ssx_critical_section_exit(&ctx);
+
+ return rc;
+}
+
+
+
+
diff --git a/src/lib/ppc405lib/mutex.h b/src/lib/ppc405lib/mutex.h
new file mode 100644
index 0000000..6d3a352
--- /dev/null
+++ b/src/lib/ppc405lib/mutex.h
@@ -0,0 +1,164 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/mutex.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __MUTEX_H__
+#define __MUTEX_H__
+
+// $Id$
+
+/// \file mutex.h
+/// \brief A ThreadX-style mutual exclusion object
+///
+/// A Mutex is a binary semaphore with the concept of thread ownership. A
+/// thread first obtains the Mutex using the mutex_pend() API, which may block
+/// if the Mutex is currently owned by another thread. Once a thread owns a
+/// Mutex, subsequent calls of mutex_pend() by the same thread simply
+/// increment an internal counter, but do not block. Once a thread has
+/// executed a matching mutex_post() call for every mutex_pend() call, the
+/// Mutex is free for another thread.
+///
+/// This type of mutual exclusion object is useful for example to control
+/// access to data structures that are manipulated by APIs with several common
+/// entry points. Each call of an API in the chain will 'lock' the data
+/// structure using mutex_pend()/mutex_post(). The Mutex semantics allows
+/// multiple "locks" by the same thread, but requires a corresponding "unlock"
+/// for every "lock".
+///
+/// The Mutex usage counter is a 32-bit unsigned integer. If a thread makes
+/// 2^32 calls to mutex_pend() without an intervening call of mutex_post(), an
+/// overflow is signalled. This error should be considered unrecoverable to
+/// the application.
+///
+/// Like the SSX semaphore, no record is kept in the thread of which Mutex
+/// objects are currently owned by the thread. If a thread terminates or is
+/// deleted while holding a Mutex it is likely that the application will
+/// hang. Unlike the SSX semaphore, it is absolutely illegal to call
+/// mutex_pend() and mutex_post() from interrupt contexts. It is also illegal
+/// for a thread to call mutex_post() for a mutex it does not own.
+///
+/// Mutex objects are easily created with the static initialization macro
+/// MUTEX_INITIALIZATION as in the following example.
+///
+/// \code
+///
+/// Mutex G_mutex = MUTEX_INITIALIZATION;
+///
+/// \endcode
+///
+/// The API mutex_create() is also provided for run-time initialization.
+
+#include "ssx.h"
+
+
+// Mutex error/panic codes
+
+#define MUTEX_OVERFLOW 0x00688901
+#define MUTEX_NOT_OWNED 0x00688902
+
+
+#ifndef __ASSEMBLER__
+
+/// Static initialization of a Mutex
+///
+/// For a full description of the Mutex please see the documentation fof the
+/// file mutex.h.
+#define MUTEX_INITIALIZATION {SSX_SEMAPHORE_INITIALIZATION(1, 1), 0, 0}
+
+
+/// The Mutex object
+
+typedef struct {
+
+ /// The binary semaphore
+ SsxSemaphore sem;
+
+ /// A pointer to the owning thread, or NULL (0)
+ SsxThread* thread;
+
+ /// The count of unmatched mutex_pend() calls made by the owning thread.
+ uint32_t count;
+
+} Mutex;
+
+
+/// Create (initialize) a Mutex
+///
+/// \param[in] i_mutex A pointer to the Mutex object to initialize.
+///
+/// For a full description of the Mutex please see the documentation for the
+/// file mutex.h.
+///
+/// \retval 0 Success
+///
+/// \retval 0 -SSX_INVALID_OBJECT The \a i_mutex is NULL (0).
+int
+mutex_create(Mutex* i_mutex);
+
+
+/// Pend on a Mutex with optional timeout
+///
+/// \param[in] i_mutex A pointer to the Mutex
+///
+/// \param[in] i_timeout Either the constant SSX_WAIT_FOREVER, or a timeout
+/// interval specification.
+///
+/// For a full description of the Mutex please see the documentation for the
+/// file mutex.h.
+///
+/// \retval 0 Success
+///
+/// \retval -SSX_INVALID_OBJECT The \a i_mutex is NULL (0).
+///
+/// \retval -SSX_ILLEGAL_CONTEXT The call was not made from a thread context.
+///
+/// \retval -SSX_SEMEPHORE_PEND_TIMED_OUT The thread was not able to obtain
+/// the Mutex before the timeout.
+///
+/// \retval -MUTEX_OVERFLOW The owning thread has made 2^32 unmatched calls of
+/// mutex_pend().
+int
+mutex_pend(Mutex* i_mutex, SsxInterval i_timeout);
+
+
+/// Post to a Mutex
+///
+/// \param[in] i_mutex A pointer to the Mutex
+///
+/// For a full description of the Mutex please see the documentation for the
+/// file mutex.h.
+///
+/// \retval 0 Success
+///
+/// \retval -SSX_INVALID_OBJECT The \a i_mutex is NULL (0).
+///
+/// \retval -SSX_ILLEGAL_CONTEXT The call was not made from a thread context.
+///
+/// \retval -MUTEX_NOT_OWNED The thread calling mutex_post() does not own the
+/// Mutex.
+int
+mutex_post(Mutex* i_mutex);
+
+#endif // __ASSEMBLER__
+
+#endif // __MUTEX_H__
diff --git a/src/lib/ppc405lib/periodic_semaphore.c b/src/lib/ppc405lib/periodic_semaphore.c
new file mode 100644
index 0000000..dec9ea2
--- /dev/null
+++ b/src/lib/ppc405lib/periodic_semaphore.c
@@ -0,0 +1,114 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/periodic_semaphore.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id$
+
+/// \file perodic_semaphore.h
+/// \brief Periodic semphores
+
+#include "ssx.h"
+#include "periodic_semaphore.h"
+
+// The timer callback is created nonpreemptible, so noncritical interrupts are
+// disabled at entry.
+
+static void
+_periodic_semaphore_timeout(void* arg)
+{
+ PeriodicSemaphore* ps;
+
+ ps = (PeriodicSemaphore*)arg;
+
+ if (ps->sem.count != 1) {
+ ssx_semaphore_post(&(ps->sem));
+ }
+}
+
+
+int
+periodic_semaphore_create(PeriodicSemaphore* sem, SsxInterval period)
+{
+ int rc;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(sem == 0, SSX_INVALID_OBJECT);
+ }
+
+ do {
+ rc = ssx_semaphore_create(&(sem->sem), 0, 1);
+ if (rc) break;
+
+ rc = ssx_timer_create_nonpreemptible(&(sem->timer),
+ _periodic_semaphore_timeout,
+ sem);
+ if (rc) break;
+
+ rc = ssx_timer_schedule(&(sem->timer),
+ period,
+ period);
+ if (rc) break;
+
+ } while (0);
+
+ return rc;
+}
+
+
+int
+periodic_semaphore_pend(PeriodicSemaphore* sem)
+{
+ int rc;
+ SsxMachineContext ctx;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(sem == 0, SSX_INVALID_OBJECT);
+ }
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ if (sem->sem.count == 0) {
+
+ rc = ssx_semaphore_pend(&(sem->sem), SSX_WAIT_FOREVER);
+
+ } else {
+
+ sem->sem.count = 0;
+ rc = -PERIODIC_SEMAPHORE_OVERRUN;
+ }
+
+ ssx_critical_section_exit(&ctx);
+
+ return rc;
+}
+
+
+int
+periodic_semaphore_cancel(PeriodicSemaphore* sem)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(sem == 0, SSX_INVALID_OBJECT);
+ }
+
+ return ssx_timer_cancel(&(sem->timer));
+}
diff --git a/src/lib/ppc405lib/periodic_semaphore.h b/src/lib/ppc405lib/periodic_semaphore.h
new file mode 100644
index 0000000..c3c2e53
--- /dev/null
+++ b/src/lib/ppc405lib/periodic_semaphore.h
@@ -0,0 +1,152 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/periodic_semaphore.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __PERIODIC_SEMAPHORE_H__
+#define __PERIODIC_SEMAPHORE_H__
+
+// $Id$
+
+/// \file perodic_semaphore.h
+/// \brief Periodic semphores
+///
+/// The PeriodicSemphore is a simple abstraction introduced to simplify coding
+/// peridic threads. A periodic thread creates the PeriodicSemaphore after
+/// thread initialization, but prior to the entry to the periodic infinite
+/// loop. This creates the periodicSemaphore with a count of 0. Once thread
+/// processing is finished, the thread pends on the PeriodicSemaphore. A
+/// periodic timer posts to the PeriodicSemaphore on a fixed, absolute period
+/// to reschedule the thread.
+///
+/// If the thread pends on the PeriodicSemaphore and the timer has already
+/// posted to the semaphore, the call of periodic_semaphore_pend() clears the
+/// semaphore and terminates immediately with the return code
+/// -PERIODIC_SEMAPHORE_OVERRUN, indicating that the thread has overrun its
+/// period. The thread can choose the appropriate action upon obtaining this
+/// return code.
+///
+/// The PeriodicSemaphore can also be cancelled, which simply cancels the
+/// periodic timer posting to the semaphore. If the thread needs to
+/// re-initialize the PeriodicSemaphore for any reason (e.g, to resynchronize
+/// after an overrun) it must be cancelled first.
+
+// Error/Panic codes
+
+#define PERIODIC_SEMAPHORE_OVERRUN 0x0077e601
+
+
+/// A periodic semaphore
+
+typedef struct {
+
+ /// The semaphore
+ SsxSemaphore sem;
+
+ /// The timer
+ SsxTimer timer;
+
+} PeriodicSemaphore;
+
+
+/// Create (initialize) a PeriodicSemaphore
+///
+/// \param sem A pointer to an uninitialized or inactive
+/// PeriodicSemaphore.
+///
+/// \param period The semaphore period
+///
+/// This API creates the embedded semaphore as a binary semaphore with an
+/// initial value of 0, and schedules a periodic timer to post to the
+/// semaphore.
+///
+/// \retval 0 Success
+///
+/// \retval -SSX_INVALID_OBJECT The \a sem was NULL (0) or otherwise invalid.
+///
+/// Other return codes are possible from the embedded calls of SSX APIs.
+int
+periodic_semaphore_create(PeriodicSemaphore* sem, SsxInterval period);
+
+
+/// Pend on a PeriodicSemaphore
+///
+/// \param sem A pointer to an initialized PeriodicSemaphore
+///
+/// Pend on a PeriodicSemaphore. It is considered a non-fatal error if the
+/// semaphore has a non-0 count as this may indicate that a periodic thread
+/// has missed a deadline.
+///
+/// Return values other than SSX_OK (0) are not necessarily errors; see \ref
+/// ssx_errors
+///
+/// The following return codes are non-error codes:
+///
+/// \retval 0 Success. In particular, the semaphore count was 0 at entry.
+///
+/// \retval -PERIODIC_SEMAPHORE_OVERRUN This return code indicates that the
+/// semaphore count was 1 at entry. This code is always returned (never causes
+/// a panic).
+///
+/// The following return codes are error codes:
+///
+/// \retval -SSX_IVALID_OBJECT The \a sem was NULL () or otherwise invalid at
+/// entry.
+///
+/// Other error return codes are possible from embedded calls of SSX APIs.
+int
+periodic_semaphore_pend(PeriodicSemaphore* sem);
+
+
+/// Cancel a periodic semaphore
+///
+/// \param sem A pointer to an initialized PeriodicSemaphore
+///
+/// Cancel the PeriodicSemaphore timeout. This is a required step if the
+/// PeriodicSemaphore is to be reinitialized. This is also required if the
+/// PeriodicSemaphore is created on the thread stack and the thread
+/// terminates. PeriodicSemaphore can be canceled at any time. It is never
+/// an error to call periodic_semaphore_cancel() on a PeriodicSemaphore object
+/// after it is created.
+///
+/// Return values other than SSX_OK (0) are not necessarily errors; see \ref
+/// ssx_errors
+///
+/// The following return codes are non-error codes:
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SSX_TIMER_NOT_ACTIVE The embedded timer is not currently
+/// scheduled, meaning that the PeriodicSemaphore was previosly
+/// cancelled.
+///
+/// The following return codes are error codes:
+///
+/// \retval -SSX_IVALID_OBJECT The \a sem was NULL () or otherwise invalid at
+/// entry.
+///
+/// Other error return codes are possible from embedded calls of SSX APIs.
+int
+periodic_semaphore_cancel(PeriodicSemaphore* sem);
+
+
+#endif // __PERIODIC_SEMAPHORE_H__
diff --git a/src/lib/ppc405lib/polling.c b/src/lib/ppc405lib/polling.c
new file mode 100644
index 0000000..a013202
--- /dev/null
+++ b/src/lib/ppc405lib/polling.c
@@ -0,0 +1,97 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/polling.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: polling.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/polling.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file polling.c
+/// \brief Library APIs for polling
+
+#include "polling.h"
+
+int
+polling(int* o_rc,
+ int (*i_condition)(void* io_arg, int* o_satisfied),
+ void* io_arg,
+ SsxInterval i_timeout,
+ SsxInterval i_sleep)
+{
+ SsxTimebase start;
+ int rc, pollRc, timed_out, done;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF((i_condition == 0), POLLING_ERROR);
+ }
+
+ start = ssx_timebase_get();
+ timed_out = 0;
+
+ do {
+ pollRc = i_condition(io_arg, &done);
+ if (pollRc) {
+ rc = POLLING_CONDITION;
+ break;
+ }
+ if (done) {
+ rc = 0;
+ break;
+ }
+ if (timed_out) {
+ rc = POLLING_TIMEOUT;
+ break;
+ }
+ if (i_sleep != 0) {
+ rc = ssx_sleep(i_sleep);
+ if (rc) {
+ break;
+ }
+ }
+ timed_out =
+ ((i_timeout != SSX_WAIT_FOREVER) &&
+ ((ssx_timebase_get() - start) >= i_timeout));
+
+ } while (1);
+
+ if (o_rc) {
+ *o_rc = pollRc;
+ }
+
+ return rc;
+}
+
+
+void
+busy_wait(SsxInterval i_interval)
+{
+ SsxTimebase start;
+
+ start = ssx_timebase_get();
+ while ((ssx_timebase_get() - start) < i_interval);
+}
+
diff --git a/src/lib/ppc405lib/polling.h b/src/lib/ppc405lib/polling.h
new file mode 100644
index 0000000..99afbe7
--- /dev/null
+++ b/src/lib/ppc405lib/polling.h
@@ -0,0 +1,118 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/polling.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __POLLING_H__
+#define __POLLING_H__
+
+// $Id: polling.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/polling.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file polling.c
+/// \brief Library APIs for polling and busy-waiting
+
+#include "ssx.h"
+
+// Return/Panic codes
+
+#define POLLING_TIMEOUT 0x00765501
+#define POLLING_ERROR 0x00765502
+#define POLLING_CONDITION 0x00765503
+
+
+#ifndef __ASSEMBLER__
+
+/// Poll for a condition or a timeout with optional sleep
+///
+/// \param[out] o_rc The last return code from calling \a i_condition. This
+/// will only be valid if the return code from polling() is
+/// POLLING_CONDITION. This argument may be passed as NULL (0) if the caller
+/// does not require this information.
+///
+/// \param[in] i_condition A function of two arguments, returning an integer
+/// return code - 0 for success, non-0 for failure. The first argument is a
+/// private state or parameter variable. The second argument is used to
+/// return the truth value of the \a i_condition predicate (0 for false, non-0
+/// for true), and is only considered if the return value of \a i_condition is
+/// 0.
+///
+/// \param[in,out] io_arg The private argument of the \a condition function.
+///
+/// \param[in] i_timeout The maximum amount of time to poll the \a condition
+/// before declaring a timeout. The special value SSX_WAIT_FOREVER can be
+/// used to specify polling without timeout.
+///
+/// \param[in] i_sleep If non-0 at entry, then the thread will sleep for this
+/// interval between polls of the condition. Otherwise the polling is
+/// continuous. polling() can only be called with i_sleep non-0 from a
+/// thread context (since interrupt contexts can not block).
+///
+/// polling() implements a generic polling protocol for conditions that can
+/// not be recognized as interrupt events. polling() polls the \a i_condition
+/// until either an error is encountered, the condition is true, or the
+/// polling times out as measured by the SSX timebase. Whenever a timeout is
+/// detected the condition is polled once more to exclude false timeouts that
+/// may have been caused by thread preemption.
+///
+/// The \a i_sleep A non-0 value of \a i_sleep specifies that the thread
+/// should sleep for the given interval between polling tries instead of
+/// polling continuously. A non-0 \a i_sleep argument is only legal in thread
+/// contexts.
+///
+/// \retval 0 Success; The condition was satisfied prior to the timeout.
+///
+/// \retval POLLING_TIMEOUT A timeout was detected before the condition became
+/// valid.
+///
+/// \retval POLLING_ERROR This code is returned if any of the arguments of
+/// polling() are invalid.
+///
+/// \retval POLLING_CONDITION This code is returned if the \a i_condition
+/// function returns a non-0 return code.
+///
+/// If the embedded call of ssx_sleep() fails for some reason then the return
+/// code will be the code returned by ssx_sleep().
+int
+polling(int* o_rc,
+ int (*i_condition)(void* io_arg, int* o_satisfied),
+ void* io_arg,
+ SsxInterval i_timeout,
+ SsxInterval i_sleep);
+
+
+/// A busy-wait loop
+///
+/// \param[in] i_interval The interval of time to busy-wait. The actual
+/// interval may be more than this if the thread is interrupted. If called
+/// from a context with interrupts disabled the timing should be very precise.
+void
+busy_wait(SsxInterval i_interval);
+
+#endif // __ASSEMBLER__
+
+#endif // __POLLING_H__
diff --git a/src/lib/ppc405lib/printf.c b/src/lib/ppc405lib/printf.c
new file mode 100644
index 0000000..d75cdf3
--- /dev/null
+++ b/src/lib/ppc405lib/printf.c
@@ -0,0 +1,703 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/printf.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: printf.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/printf.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file printf.c
+/// \brief Clean-room implementation of printf() functions for SSX I/O
+///
+/// For licensing reasons we are required to create our own version of the
+/// printf() family of functions. This implementation was created without
+/// reference to or inclusion of any licensed or copyrighted code.
+///
+/// The functions defined in this file have prototypes, behavior and return
+/// values as defined by C language standards. In the event of an error a
+/// negative value is returned, generally corresponding to a standard Unix
+/// 'errno' code. Note that SSX does not support either an application- or
+/// per-thread 'errno', so the only record of any error is the \a error field
+/// of the stream. Also note that SSX may be configured to cause a panic if an
+/// error is detected rather than returning an error code.
+///
+/// This implementation defines a limited but useful subset of the C standard
+/// for format control. This implementation includes the following:
+///
+/// - \b c, \b d, \b i, \b n, \b p, \b s, \b u, \b x, and \b X conversion
+/// specifiers, as well as '%%' to output a single '%'
+///
+/// - \b #, \b 0, \b ' ' and \b + flag characters
+///
+/// - Decimal field width specifiers including * (but indirect field widths
+/// must be positive as left-justification is not supported)
+///
+/// - Decimal precision specifiers (currently only apply to %s formats, may be
+/// indirect using *)
+///
+/// - \b l, \b ll and \b z length modifiers
+///
+/// \b Notes:
+///
+/// \a If a \c p conversion specifier is used without any flags (\c '%p'), the
+/// \c p conversion is interptered as if it were \c 0x%08lx for 32-bit address
+/// machines and \c 0x%016llx for 64-bit address machines. The GCC builtin
+/// format checker gives warnings about '0' flag characters for \c p
+/// conversion specifiers, so there is otherwise no 'un-warned' way to get
+/// this preferred (by some) format of pointer values. If you do include
+/// explicit flags (e.g., \c %30p) they will be processed as expected.
+///
+/// Similar to how printf() behaves on an X86-Linux machine, a null pointer
+/// will print as "(null)" with the %s format (unless the precision specifier
+/// precludes it) and "(nil)" with the %p format.
+///
+/// Note that calling formatted I/O functions on non-blocking streams may fail
+/// with the -EAGAIN error, and there is no clean way to restart these
+/// calls. Calling formatted (or any) I/O functions on blocking streams from
+/// interrupt contexts in SSX is also likely to fail intermittently since
+/// interrupt contexts can not block in SSX.
+///
+/// \todo I'd really like to implement the '-' flag for
+/// left-justification. Implementing the precision specifer for integers
+/// should be done for completeness.
+
+#include "ssx.h"
+#include "ssx_io.h"
+
+// Formatting options
+
+#define OPTION_ALTERNATE 0x0001
+#define OPTION_PAD_ZERO 0x0002
+#define OPTION_PLUS_SIGN 0x0004
+#define OPTION_FIELD_WIDTH 0x0008
+#define OPTION_PRECISION 0x0010
+#define OPTION_LONG 0x0020
+#define OPTION_LONG_LONG 0x0040
+#define OPTION_SIZE_T 0x0080
+#define OPTION_UPPERCASE 0x0100
+#define OPTION_HEX 0x0200
+#define OPTION_SPACE 0x0400
+
+
+// Generate padding if required, returning the total number of pad characters
+// output or a negative error code. The 'nchars' argument is the number of
+// non-pad characters to be output by the caller.
+
+#define PAD_SIZE 8
+static const char zeros[PAD_SIZE] = {'0', '0', '0', '0', '0', '0', '0', '0'};
+static const char blanks[PAD_SIZE] = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '};
+
+static ssize_t
+pad(FILE *stream, size_t nchars, int options, size_t width)
+{
+ const char *padchars;
+ size_t chars, written;
+ int rc;
+
+ if (!(options & OPTION_FIELD_WIDTH) || (nchars >= width)) {
+ return 0;
+ }
+ chars = width - nchars;
+ if (options & OPTION_PAD_ZERO) {
+ padchars = zeros;
+ } else {
+ padchars = blanks;
+ }
+ while (chars) {
+ rc = swrite(stream, (void *)padchars, MIN(chars, PAD_SIZE), &written);
+ if (rc < 0) return rc;
+ chars -= written;
+ }
+ return width - nchars;
+}
+
+
+// Format a character
+
+static ssize_t
+format_char(FILE *stream, unsigned char c, int options, size_t width)
+{
+ ssize_t padchars, nchars;
+ int rc;
+
+ padchars = pad(stream, 1, options, width);
+ if (padchars < 0) return padchars;
+ nchars = padchars + 1;
+ rc = swrite(stream, (void *)(&c), 1, 0);
+ if (rc < 0) return rc;
+ return nchars;
+}
+
+
+// Format a string
+//
+// If the string is the NULL pointer then normally "(null)" is printed
+// unless the precision is < 6, in which case the empty string is printed.
+// The specification leaves it as undefined what happens if a string requests
+// 0 padding; Here we always pad with blanks (although GCC/PowerPC catches
+// this as an error).
+
+static ssize_t
+format_string(FILE *stream, const char *s, int options,
+ size_t width, size_t precision)
+{
+ size_t len;
+ ssize_t padchars, nchars;
+ int rc;
+
+ if (s == 0) {
+ if ((options & OPTION_PRECISION) && (precision < 6)) {
+ s = "";
+ } else {
+ s = "(null)";
+ }
+ }
+
+ len = strlen(s);
+ if (options & OPTION_PRECISION) {
+ len = MIN(len, precision);
+ }
+
+ options &= ~OPTION_PAD_ZERO;
+ padchars = pad(stream, len, options, width);
+ if (padchars < 0) return padchars;
+ nchars = padchars + len;
+ rc = swrite(stream, (void *)s, len, 0);
+ if (rc < 0) return rc;
+ return nchars;
+}
+
+
+// Format an integer - signed and unsigned. A 64-bit integer (assumed to be
+// the longest we'll see) has 20 decimal digits. An extra space is reserved
+// for the sign. If zero-padding is specified, the sign will be output
+// separately.
+
+static const char lower[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+static const char upper[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+static ssize_t
+format_int(FILE *stream, long long int lli, int options, size_t width)
+{
+ char digits[21];
+ int rc, k, ndigits, negative, positive, i;
+ ssize_t output;
+
+ negative = (lli < 0);
+ positive = (lli > 0);
+
+ // Unpack the integer to characters. The code is optimized for 32-bit
+ // machines where 64-bit division is not built in. The first part of the
+ // loop handles integers requiring a 64-bit divide, the second loop
+ // handles 32-bit integers.
+
+ if (lli == 0) {
+ digits[20] = '0';
+ k = 20;
+ } else if (negative) {
+ for (k = 21;
+ lli != (int)lli;
+ digits[--k] = lower[-(lli % 10)], lli = lli / 10);
+ for (i = (int)lli;
+ i != 0;
+ digits[--k] = lower[-(i % 10)], i = i / 10);
+ } else {
+ for (k = 21;
+ lli != (int)lli;
+ digits[--k] = lower[lli % 10], lli = lli / 10);
+ for (i = (int)lli;
+ i != 0;
+ digits[--k] = lower[i % 10], i = i / 10);
+ }
+
+ ndigits = 21 - k;
+
+ // Handle other options and output
+
+ output = 0;
+ if (options & OPTION_PAD_ZERO) {
+
+ if (negative) {
+ rc = swrite(stream, "-", 1, 0);
+ if (rc < 0) return rc;
+ output++;
+ } else if (positive) {
+ if (options & OPTION_PLUS_SIGN) {
+ rc = swrite(stream, "+", 1, 0);
+ if (rc < 0) return rc;
+ output++;
+ } else if (options & OPTION_SPACE) {
+ rc = swrite(stream, " ", 1, 0);
+ if (rc < 0) return rc;
+ output++;
+ }
+ }
+ rc = pad(stream, ndigits + output, options, width);
+ if (rc < 0) return rc;
+ output += rc;
+ rc = swrite(stream, &(digits[k]), ndigits, 0);
+ if (rc < 0) return rc;
+ output += ndigits;
+
+ } else {
+
+ if (negative) {
+ digits[--k] = '-';
+ ndigits++;
+ } else if (positive) {
+ if (options & OPTION_PLUS_SIGN) {
+ digits[--k] = '+';
+ ndigits++;
+ } else if (options & OPTION_SPACE) {
+ digits[--k] = ' ';
+ ndigits++;
+ }
+ }
+ rc = pad(stream, ndigits, options, width);
+ if (rc < 0) return rc;
+ output += rc;
+ rc = swrite(stream, &(digits[k]), ndigits, 0);
+ if (rc < 0) return rc;
+ output += ndigits;
+ }
+
+ return output;
+}
+
+
+static ssize_t
+format_unsigned(FILE *stream, unsigned long long ull, int options, size_t width)
+{
+ char digits[21], *alternate;
+ const char *xchars;
+ int rc, k, ndigits, zero;
+ unsigned u;
+ ssize_t output;
+
+ zero = (ull == 0);
+
+ // Determine hex case and alternate string
+
+ alternate = 0;
+ if (options & OPTION_HEX) {
+ if (options & OPTION_UPPERCASE) {
+ xchars = upper;
+ if (options & OPTION_ALTERNATE) {
+ alternate = "0X";
+ }
+ } else {
+ xchars = lower;
+ if (options & OPTION_ALTERNATE) {
+ alternate = "0x";
+ }
+ }
+ } else {
+ xchars = lower;
+ }
+
+ // Unpack the unsigned integer to characters. The Hex conversions are
+ // easier since they can be done with shift and mask rather than
+ // divison. The code is optimized for a 32-bit machine where 64-bit
+ // division is not built-in.
+
+ if (zero) {
+ digits[20] = '0';
+ k = 20;
+ } else if (options & OPTION_HEX) {
+ for (k = 21;
+ ull != (unsigned)ull;
+ digits[--k] = xchars[ull & 0xf], ull = ull >> 4);
+ for (u = (unsigned)ull;
+ u != 0;
+ digits[--k] = xchars[u & 0xf], u = u >> 4);
+ } else {
+ for (k = 21;
+ ull != (unsigned)ull;
+ digits[--k] = xchars[ull % 10], ull = ull / 10);
+ for (u = (unsigned)ull;
+ u != 0;
+ digits[--k] = xchars[u % 10], u = u / 10);
+ }
+
+ ndigits = 21 - k;
+
+ // Handle other options and output
+
+ output = 0;
+ if (options & OPTION_PAD_ZERO) {
+
+ if (!zero && alternate) {
+ rc = swrite(stream, (void *)alternate, 2, 0);
+ if (rc < 0) return rc;
+ output += 2;
+ }
+ rc = pad(stream, ndigits + output, options, width);
+ if (rc < 0) return rc;
+ output += rc;
+ rc = swrite(stream, &(digits[k]), ndigits, 0);
+ if (rc < 0) return rc;
+ output += ndigits;
+
+ } else {
+
+ if (!zero && alternate) {
+ output += 2;
+ }
+ rc = pad(stream, ndigits + output, options, width);
+ if (rc < 0) return rc;
+ output += rc;
+ if (!zero && alternate) {
+ rc = swrite(stream, alternate, 2, 0);
+ if (rc < 0) return rc;
+ output += 2;
+ }
+ rc = swrite(stream, &(digits[k]), ndigits, 0);
+ if (rc < 0) return rc;
+ output += ndigits;
+ }
+
+ return output;
+}
+
+
+int
+vfprintf(FILE *stream, const char *format, va_list argp)
+{
+ const char *fmt, *scan;
+ int rc, total_chars, options, done;
+ size_t width, precision;
+
+ int arg_i, *arg_pi;
+ long int arg_li;
+ long long int arg_lli;
+ ssize_t arg_zi;
+ unsigned arg_u;
+ unsigned long arg_lu;
+ unsigned long long arg_llu;
+ size_t arg_zu;
+ char *arg_s;
+
+ total_chars = 0;
+
+ fmt = format;
+ while (*fmt) {
+
+ // Scan until '%' or the end of the format, then output the text.
+
+ scan = fmt;
+ while (*scan && (*scan != '%')) {
+ scan++;
+ }
+ if (scan != fmt) {
+ rc = swrite(stream, fmt, scan - fmt, 0);
+ if (rc < 0) return rc;
+ total_chars += scan - fmt;
+ }
+ fmt = scan;
+ if (!*fmt) {
+ return total_chars;
+ }
+ fmt++;
+
+ // We got a '%'. Check for %% and %n.
+
+ switch (*fmt) {
+ case '\0':
+ SSX_IO_ERROR(stream, EINVAL);
+ break;
+ case '%':
+ rc = swrite(stream, "%", 1, 0);
+ if (rc < 0) return rc;
+ total_chars++;
+ fmt++;
+ continue;
+ case 'n':
+ arg_pi = va_arg(argp, int *);
+ *arg_pi = total_chars;
+ fmt++;
+ continue;
+ }
+
+ // Collect padding options, if any. Left justification is not
+ // implemeted.
+
+ options = 0;
+ done = 0;
+ do {
+ switch (*fmt) {
+ case '\0':
+ SSX_IO_ERROR(stream, EINVAL);
+ break;
+ case '#':
+ options |= OPTION_ALTERNATE;
+ break;
+ case '0':
+ options |= OPTION_PAD_ZERO;
+ break;
+ case '+':
+ options |= OPTION_PLUS_SIGN;
+ break;
+ case ' ':
+ options |= OPTION_SPACE;
+ break;
+ case '-':
+ SSX_IO_ERROR(stream, EINVAL); // Left just. not impl.
+ break;
+ default:
+ done = 1;
+ break;
+ }
+ if (!done) {
+ fmt++;
+ }
+ } while (!done);
+
+ // Collect the field width, if specified. A negative precision
+ // specified as an argument indicates left justification (not
+ // implemented).
+
+ width = 0;
+ if (isdigit(*fmt)) {
+ options |= OPTION_FIELD_WIDTH;
+ for (; isdigit(*fmt); fmt++) {
+ width = (width * 10) + (*fmt - '0');
+ }
+ } else if (*fmt == '*') {
+ fmt++;
+ options |= OPTION_FIELD_WIDTH;
+ arg_i = va_arg(argp, int);
+ if (arg_i < 0) {
+ SSX_IO_ERROR(stream, EINVAL); // Left just. not impl.
+ }
+ width = arg_i;
+ }
+
+ // Collect the precision, if specified. By standard specification an
+ // empty or negative precision is interpreted as 0.
+
+ precision = 0;
+ if (*fmt == '.') {
+ fmt++;
+ options |= OPTION_PRECISION;
+ if (isdigit(*fmt)) {
+ for(; isdigit(*fmt); fmt++) {
+ precision = (precision * 10) + (*fmt - '0');
+ }
+ } else if (*fmt == '*') {
+ fmt++;
+ arg_i = va_arg(argp, int);
+ if (arg_i < 0) {
+ arg_i = 0;
+ }
+ precision = arg_i;
+ }
+ }
+
+ // Collect length modifiers.
+
+ done = 0;
+ do {
+ switch (*fmt) {
+ case '\0':
+ SSX_IO_ERROR(stream, EINVAL);
+ break;
+ case 'l':
+ if (options & OPTION_LONG) {
+ options &= ~OPTION_LONG;
+ options |= OPTION_LONG_LONG;
+ } else if (options & OPTION_LONG_LONG) {
+ SSX_IO_ERROR(stream, EINVAL);
+ } else {
+ options |= OPTION_LONG;
+ }
+ if (options & OPTION_SIZE_T) {
+ SSX_IO_ERROR(stream, EINVAL);
+ }
+ break;
+ case 'z':
+ if ((options & OPTION_LONG) || (options & OPTION_LONG_LONG)) {
+ SSX_IO_ERROR(stream, EINVAL);
+ }
+ options |= OPTION_SIZE_T;
+ break;
+ default:
+ done = 1;
+ break;
+ }
+ if (!done) {
+ fmt++;
+ }
+ } while (!done);
+
+ // Use the conversion specifier to format the next argument
+
+ switch (*fmt) {
+
+ case 'c':
+ arg_i = va_arg(argp, int);
+ rc = format_char(stream, (unsigned char)arg_i, options, width);
+ if (rc < 0) return rc;
+ total_chars++;
+ break;
+
+ case 'd':
+ case 'i':
+ if (options & OPTION_LONG) {
+ arg_li = va_arg(argp, long int);
+ rc = format_int(stream, (long long int)arg_li, options,
+ width);
+ } else if (options & OPTION_LONG_LONG) {
+ arg_lli = va_arg(argp, long long int);
+ rc = format_int(stream, (long long int)arg_lli, options,
+ width);
+ } else if (options & OPTION_SIZE_T) {
+ arg_zi = va_arg(argp, ssize_t);
+ rc = format_int(stream, (long long int)arg_zi, options,
+ width);
+ } else {
+ arg_i = va_arg(argp, int);
+ rc = format_int(stream, (long long int)arg_i, options,
+ width);
+ }
+ if (rc < 0) return rc;
+ total_chars += rc;
+ break;
+
+ case 'p':
+ arg_lu = va_arg(argp, unsigned long);
+ options |= (OPTION_ALTERNATE | OPTION_HEX);
+ if (!(options & OPTION_PAD_ZERO) &&
+ !(options & OPTION_FIELD_WIDTH)) {
+ options |= (OPTION_PAD_ZERO | OPTION_FIELD_WIDTH);
+ width = (2 * sizeof(unsigned long)) + 2; /* 0x........ */
+ }
+ if (arg_lu == 0) {
+ options &= ~OPTION_PRECISION;
+ rc = format_string(stream, "(nil)", options, width, precision);
+ } else {
+ rc = format_unsigned(stream, (unsigned long long)arg_lu,
+ options, width);
+ }
+ if (rc < 0) return rc;
+ total_chars += rc;
+ break;
+
+ case 's':
+ arg_s = va_arg(argp, char *);
+ rc = format_string(stream, arg_s, options, width, precision);
+ if (rc < 0) return rc;
+ total_chars += rc;
+ break;
+
+ case 'X':
+ options |= OPTION_UPPERCASE;
+ case 'x':
+ options |= OPTION_HEX;
+ case 'u':
+ if (options & OPTION_LONG) {
+ arg_lu = va_arg(argp, unsigned long);
+ rc = format_unsigned(stream, (unsigned long long)arg_lu,
+ options, width);
+ } else if (options & OPTION_LONG_LONG) {
+ arg_llu = va_arg(argp, unsigned long long);
+ rc = format_unsigned(stream, (unsigned long long)arg_llu,
+ options, width);
+ } else if (options & OPTION_SIZE_T) {
+ arg_zu = va_arg(argp, size_t);
+ rc = format_unsigned(stream, (unsigned long long)arg_zu,
+ options, width);
+ } else {
+ arg_u = va_arg(argp, unsigned);
+ rc = format_unsigned(stream, (unsigned long long )arg_u,
+ options, width);
+ }
+ if (rc < 0) return rc;
+ total_chars += rc;
+ break;
+
+ default:
+ SSX_IO_ERROR(stream, EINVAL);
+ break;
+ }
+
+ fmt++;
+ }
+
+ return total_chars;
+}
+
+
+int
+vprintf(const char *format, va_list argp)
+{
+ return vfprintf(stdout, format, argp);
+}
+
+
+int
+fprintf(FILE *stream, const char *format, ...)
+{
+ va_list argp;
+ int rc;
+
+ va_start(argp, format);
+ rc = vfprintf(stream, format, argp);
+ va_end(argp);
+ return rc;
+}
+
+
+int
+printf(const char *format, ...)
+{
+ va_list argp;
+ int rc;
+
+ va_start(argp, format);
+ rc = vfprintf(stdout, format, argp);
+ va_end(argp);
+ return rc;
+}
+
+
+int
+printk(const char *format, ...)
+{
+ va_list argp;
+ int rc;
+
+ va_start(argp, format);
+ rc = vfprintf(ssxout, format, argp);
+ va_end(argp);
+ return rc;
+}
+
diff --git a/src/lib/ppc405lib/progress.c b/src/lib/ppc405lib/progress.c
new file mode 100644
index 0000000..8d2cd30
--- /dev/null
+++ b/src/lib/ppc405lib/progress.c
@@ -0,0 +1,743 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/progress.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id
+
+/// \file progress.c
+/// \brief Programmable progress (hang) checking
+///
+/// This is a simple implementation of a progress (hang) checking
+/// facility. The application provides an array of \e pass \e counts that are
+/// expected to update/count over time. For simplicity and generality all
+/// pass counts are defined to be \c uint64_t types. The
+/// progress_checker_create() API initializes the checker, and as a
+/// convenience clears the pass counts.
+///
+/// The checker can be created with an optional \a callback function, which
+/// has the prototype
+///
+/// \code
+/// typedef int (*ProgressCheckerCallback)(struct ProgressChecker *checker,
+/// void* arg,
+/// size_t failed)
+/// \endcode
+///
+/// The checker callback is called \e every time a check is made by
+/// progress_checker_check(). In addition to a private void* argument, the
+/// parameter list of the callback includes a count of the number of counters
+/// that failed to make progress - this count will be 0 if the check was
+/// successful. The return value of the callback is passed back as the return
+/// value of progress_checker_check(). If the callback is specified as NULL
+/// (0), then a successful check returns 0, and any failure causes a return
+/// code of -PROGRESS_CHECKER_FAILED.
+///
+/// The application can dynamically mark counters as either \e exempt or \e
+/// required. By default all counts are required to have increased
+/// each time a check is made for progress. Counters marked \e exempt when a
+/// progress check is made are not checked for progress.
+///
+/// The application can also use the progress_checker_schedule() API to
+/// schedule either one-shot or periodic checks. The
+/// progress_checker_cancel() API can be used to cancel any scheduled
+/// checks. It is never an error to call this API, even if no checks are
+/// currently scheduled. Note that each call of progress_checker_schedule()
+/// also cancels any outstanding scheduled requests before (re-) scheduling
+/// the checker. If using the built-in timer mechanism, any calls of
+/// progress_checker_check that return a non-0 value will cause a kernel panic.
+///
+/// If failures are detected and caught, the ProgressChecker provides a
+/// primitive iteration facility for the callback or the applicaton to
+/// determine which counters have failed to update. Calling
+/// progress_checker_next_failure() returns either the index of the next
+/// failing counter, or -1 to indicate no more failures. This iteration
+/// facility is reset every time a check is made by progress_checker_check()
+/// (including those made implcitly by the timer-based mechanism). There is no
+/// API to reset the iteration.
+///
+/// The implemetation provides 2 standard callback functions:
+/// progess_checker_printk() and progress_checker_printk_dump(). The former
+/// callback uses printk() to print a simple report of failed counters, and if
+/// there were any failures it then returns its argument as a return code. If
+/// the return code is non-zero then the lack of progress will cause a kernel
+/// panic (test failure). The later callback first calls
+/// progress_checker_printk(). If progress_checker_printk() returns a non-0
+/// value then progress_checker_printk_dump() enters an SSX_CRITICAL crictal
+/// section and prints a full kernel state dump that may be useful to help
+/// diagnose the hang.
+///
+/// \note We do not make the kernel dump the default or only behavior because
+/// it could take 1ms or more to produce the large quantity of formatted
+/// output required, which could be a significant amount of wall time in a
+/// logic simulation environment.
+///
+/// The progress_checker_create() API could be used in a couple of ways as
+/// illustrated below:
+///
+/// \code
+///
+/// ProgressChecker progress;
+/// uint64_t counter;
+///
+/// progress_checker_create(&progress, "progress", counter, 1,
+/// progress_checker_printk,
+/// (void*)-PROGRESS_CHECKER_FAILED);
+///
+/// OR
+///
+/// progress_checker_create(&progress, "progress", counter, 1,
+/// progress_checker_printk, 0);
+///
+/// \endcode
+///
+/// The first usage prints a report and panics the test if lack of progress is
+/// detected. The second form simply prints a report in the event of a lack
+/// or progress. The second form may be useful to report on counters that
+/// only have a statistical probability of making progress, however be aware
+/// that the report is generated in an interrupt context and all thread
+/// activity will be blocked until the formatted I/O is complete.
+///
+/// Notes:
+///
+/// This implementation requires the \c byte_pool facility and malloc() to be
+/// set up as the ProgressChecker allocates dynamic storage during
+/// initialization to store the previous pass counts.
+///
+/// It is probably not a good idea to use a single ProgressChecker for both
+/// manual and timer-based checking, since there is no protection in the
+/// implementation for mutiple accesses to the ProgressChecker.
+
+#include "progress.h"
+#include "ssx_dump.h"
+
+// The built-in timer callback
+
+static void
+progress_callback(void *arg)
+{
+ ProgressChecker *checker = (ProgressChecker *)arg;
+
+ if (progress_checker_check(checker)){
+ if (0) {
+ progress_checker_dump(checker);
+ }
+ SSX_PANIC(PROGRESS_CHECKER_FAILED);
+ }
+}
+
+
+// Bit-vector operations manage the array of bits using little-endian
+// protocols
+
+static inline void
+bit_vector_set(uint8_t *vector, size_t bit)
+{
+ vector[bit / 8] |= (1 << (bit % 8));
+}
+
+
+static inline void
+bit_vector_clear(uint8_t *vector, size_t bit)
+{
+ vector[bit / 8] &= ~(1 << (bit % 8));
+}
+
+
+static inline int
+bit_vector_is_set(uint8_t *vector, size_t bit)
+{
+ return ((vector[bit / 8] & (1 << (bit % 8))) != 0);
+}
+
+
+// NB: We don't have a bit-vector object with a size included. For this
+// application we can only call this API if we know that there is at least 1
+// bit set in the vector.
+
+static size_t
+bit_vector_find_first_set(uint8_t *vector)
+{
+ size_t byte = 0;
+
+ while (vector[byte] == 0) {
+ byte++;
+ }
+
+ return (8 * byte) + __builtin_ffs(vector[byte]) - 1;
+}
+
+
+/// Create a progress checker
+///
+/// \param checker A pointer to an uninitialized or idle ProgressChecker
+///
+/// \param name An optional character string associated with the checker
+///
+/// \param pass_counts An array of pass counters - the array will be cleared
+/// by this API.
+///
+/// \param counters The number of counters in the array
+///
+/// \param callback This function is called \e every time a check is
+/// completed.
+///
+/// \param arg The private argument of the callback function
+///
+/// For an overview of the ProgressChecker and its APIs, see the documentation
+/// for the file progress.c
+///
+/// Return values other than 0 are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -PROGRESS_CHECKER_INVALID_OBJECT A null (0) pointer was provided
+/// as the \a checker argument.
+///
+/// \retval -PROGRESS_CHECKER_INVALID_ARGUMENT A null (0) pointer was provided
+/// as the \a pass_counts argument, or the number of \a counters can not be
+/// represented as a signed integer.
+///
+/// \retval -PROGRESS_CHECKER_ALLOCATION_FAILED Memory allocation of dynamic
+/// memory failed. This is treated as a fatal error here.
+///
+/// This API may also return or signal other errors from its implementation
+/// APIs.
+
+int
+progress_checker_create(ProgressChecker *checker,
+ const char* name,
+ uint64_t *pass_counts,
+ size_t counters,
+ ProgressCheckerCallback callback,
+ void *arg)
+{
+ int rc, bytes;
+ void *memory;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF((checker == 0),
+ PROGRESS_CHECKER_INVALID_OBJECT);
+ SSX_ERROR_IF((pass_counts == 0) ||
+ (counters != (int)counters),
+ PROGRESS_CHECKER_INVALID_ARGUMENT);
+ }
+
+ // Install and clear the counters
+
+ checker->pass_counts = pass_counts;
+ memset((void *)pass_counts, 0, counters * sizeof(uint64_t));
+ checker->counters = counters;
+
+ // Allocate and clear dynamic memory
+
+ memory = calloc(counters, sizeof(uint64_t));
+ checker->saved_counts = (uint64_t *)memory;
+
+ bytes = (counters / 8) + (counters % 8 ? 1 : 0);
+ checker->bit_vector_bytes = bytes;
+
+ memory = calloc(bytes, 1);
+ checker->exempt = (uint8_t *)memory;
+
+ memory = calloc(bytes, 1);
+ checker->failure = (uint8_t *)memory;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF((counters != 0) &&
+ ((checker->saved_counts == 0) ||
+ (checker->exempt == 0) ||
+ (checker->failure == 0)),
+ PROGRESS_CHECKER_ALLOCATION_FAILED);
+ }
+
+ // Initialize other fields
+
+ checker->name = name;
+ checker->callback = callback;
+ checker->arg = arg;
+ checker->failed = 0;
+ checker->checks = 0;
+
+ // Initialize the timer structure.
+
+ rc = ssx_timer_create(&(checker->timer),
+ progress_callback,
+ (void *)checker);
+ if (rc) return rc;
+
+ return 0;
+}
+
+
+/// Exempt a pass count from progress checking
+///
+/// \param checker A pointer to an initialized ProgressChecker
+///
+/// \param counter The index of the counter to exempt
+///
+/// For an overview of the ProgressChecker and its APIs, see the documentation
+/// for the file progress.c
+///
+/// Return values other than 0 are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -PROGRESS_CHECKER_INVALID_OBJECT A null (0) pointer was provided
+/// as the \a checker argument.
+///
+/// \retval -PROGRESS_CHECKER_INVALID_ARGUMENT The \a counter argument is not
+/// valid.
+
+int
+progress_checker_exempt(ProgressChecker *checker,
+ size_t counter)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(checker == 0,
+ PROGRESS_CHECKER_INVALID_OBJECT);
+ SSX_ERROR_IF(counter >= checker->counters,
+ PROGRESS_CHECKER_INVALID_ARGUMENT);
+ }
+
+ bit_vector_set(checker->exempt, counter);
+
+ return 0;
+}
+
+
+/// Exempt all pass counts from progress checking
+///
+/// \param checker A pointer to an initialized ProgressChecker
+///
+/// For an overview of the ProgressChecker and its APIs, see the documentation
+/// for the file progress.c
+///
+/// This API is provided to support applications where pass-count-updating
+/// processes are added dynamically. This API coule typically be called
+/// immediately after progress_checker_create(). Them, as each process was
+/// created it would call progress_checker_require() for the pass count.
+///
+/// Return values other than 0 are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -PROGRESS_CHECKER_INVALID_OBJECT A null (0) pointer was provided
+/// as the \a checker argument.
+int
+progress_checker_exempt_all(ProgressChecker *checker)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(checker == 0,
+ PROGRESS_CHECKER_INVALID_OBJECT);
+ }
+
+ memset(checker->exempt, -1, checker->bit_vector_bytes);
+
+ return 0;
+}
+
+
+/// Require a pass count to update for progress checking
+///
+/// \param checker A pointer to an initialized ProgressChecker
+///
+/// \param counter The index of the counter to require
+///
+/// For an overview of the ProgressChecker and its APIs, see the documentation
+/// for the file progress.c
+///
+/// Return values other than 0 are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -PROGRESS_CHECKER_INVALID_OBJECT A null (0) pointer was provided
+/// as the \a checker argument.
+///
+/// \retval -PROGRESS_CHECKER_INVALID_ARGUMENT The \a counter argument is not
+/// valid.
+
+int
+progress_checker_require(ProgressChecker *checker,
+ size_t counter)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(checker == 0,
+ PROGRESS_CHECKER_INVALID_OBJECT);
+ SSX_ERROR_IF(counter >= checker->counters,
+ PROGRESS_CHECKER_INVALID_ARGUMENT);
+ }
+
+ bit_vector_clear(checker->exempt, counter);
+
+ return 0;
+}
+
+
+/// Require a pass count to update for progress checking avoiding races
+///
+/// \param checker A pointer to an initialized ProgressChecker
+///
+/// \param counter The index of the counter to require
+///
+/// For an overview of the ProgressChecker and its APIs, see the documentation
+/// for the file progress.c
+///
+/// If a pass counter is marked "exempt" but then later marked "required",
+/// there is a potential race between the update of the pass counter and the
+/// next check, particularly when the checker is scheduled periodically. This
+/// form of the progress_checker_require() marks the progress checker such
+/// that \e all checks are deferred on the next call of
+/// progress_checker_check() targeting the object in order to avoid the race.
+///
+/// Return values other than 0 are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -PROGRESS_CHECKER_INVALID_OBJECT A null (0) pointer was provided
+/// as the \a checker argument.
+///
+/// \retval -PROGRESS_CHECKER_INVALID_ARGUMENT The \a counter argument is not
+/// valid.
+int
+progress_checker_require_defer(ProgressChecker *checker,
+ size_t counter)
+{
+ int rc;
+ SsxMachineContext ctx;
+
+ ssx_critical_section_enter(SSX_CRITICAL, &ctx);
+
+ rc = progress_checker_require(checker, counter);
+ checker->defer = 1;
+
+ ssx_critical_section_exit(&ctx);
+
+ return rc;
+}
+
+
+/// Check for progress in every required pass counter.
+///
+/// \param checker A pointer to an initialized ProgressChecker
+///
+/// For an overview of the ProgressChecker and its APIs, see the documentation
+/// for the file progress.c
+///
+/// Return values other than 0 are not necessarily errors; see \ref
+/// ssx_errors
+///
+/// \retval various Except for the error listed below,
+/// progress_checker_check() returns the code returned by the callback
+/// function. If no callback was provided when the checker was created, then 0
+/// is returned for success and -PROGRESS_CHECKER_FAILED is returned in the
+/// event of a lack of progress.
+///
+/// \retval -PROGRESS_CHECKER_INVALID_OBJECT A null (0) pointer was provided
+/// as the \a checker argument.
+
+int
+progress_checker_check(ProgressChecker *checker)
+{
+ size_t i;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(checker == 0,
+ PROGRESS_CHECKER_INVALID_OBJECT);
+ }
+
+ // Avoid doing this step unless necessary
+
+ if (checker->failed != 0) {
+ checker->failed = 0;
+ memset((void *)checker->failure, 0, checker->bit_vector_bytes);
+ }
+
+ // Check, unless checking has been deferred for 1 time by
+ // progress_checker_require_defer().
+
+ if (checker->defer) {
+
+ checker->defer = 0;
+
+ } else {
+
+ SSX_ATOMIC(SSX_CRITICAL, checker->start_check = ssx_timebase_get());
+
+ for (i = 0; i < checker->counters; i++) {
+
+ if ((checker->pass_counts[i] <= checker->saved_counts[i]) &&
+ !(bit_vector_is_set(checker->exempt, i))) {
+
+ checker->failed++;
+ bit_vector_set(checker->failure, i);
+ }
+ checker->saved_counts[i] = checker->pass_counts[i];
+ }
+
+ SSX_ATOMIC(SSX_CRITICAL, checker->end_check = ssx_timebase_get());
+ }
+
+ checker->checks++;
+
+ if (checker->callback) {
+ return checker->callback(checker, checker->arg, checker->failed);
+ } else if (checker->failed != 0) {
+ return -PROGRESS_CHECKER_FAILED;
+ } else {
+ return 0;
+ }
+}
+
+
+/// Schedule progress checks (periodically) in the future.
+///
+/// \param checker A pointer to an initialized ProgressChecker
+///
+/// \param interval The relative time of the (first) check
+///
+/// \param period If non-zero, checks will be made periodically with this
+/// period.
+///
+/// For an overview of the ProgressChecker and its APIs, see the documentation
+/// for the file progress.c. See the SSX documentation for a discussion of
+/// timer scheduling in SSX.
+///
+/// Return values other than 0 errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -PROGRESS_CHECKER_INVALID_OBJECT A null (0) pointer was provided
+/// as the \a checker argument.
+///
+/// This API may also return or signal other errors from its implementation
+/// APIs.
+
+
+int
+progress_checker_schedule(ProgressChecker *checker,
+ SsxInterval interval,
+ SsxInterval period)
+{
+ int rc;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(checker == 0,
+ PROGRESS_CHECKER_INVALID_OBJECT);
+ }
+
+ rc = ssx_timer_cancel(&(checker->timer));
+ if (rc != -SSX_TIMER_NOT_ACTIVE) return rc;
+
+ rc = ssx_timer_schedule(&(checker->timer), interval, period);
+ if (rc) return rc;
+
+ return 0;
+}
+
+
+/// Cancel all future (periodic) progress checks
+///
+/// \param checker A pointer to an initialized ProgressChecker
+///
+/// For an overview of the ProgressChecker and its APIs, see the documentation
+/// for the file progress.c. See the SSX documentation for a discussion of
+/// timer scheduling in SSX.
+///
+/// Return values other than 0 errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -PROGRESS_CHECKER_INVALID_OBJECT A null (0) pointer was provided
+/// as the \a checker argument.
+///
+/// This API may also return or signal other errors from its implementation
+/// APIs.
+
+int
+progress_checker_cancel(ProgressChecker *checker)
+{
+ int rc;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(checker == 0,
+ PROGRESS_CHECKER_INVALID_OBJECT);
+ }
+
+ rc = ssx_timer_cancel(&(checker->timer));
+ if (rc) return rc;
+
+ return 0;
+}
+
+
+/// Iterate over progress check failures
+///
+/// \param checker A pointer to an initialized ProgressChecker
+///
+/// \param counter Will return the index of the next failing counter, or -1 to
+/// indicate no more failing counters.
+///
+/// For an overview of the ProgressChecker and its APIs, see the documentation
+/// for the file progress.c.
+///
+/// Return values other than 0 errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -PROGRESS_CHECKER_INVALID_OBJECT A null (0) pointer was provided
+/// as the \a checker argument.
+
+int
+progress_checker_next_failure(ProgressChecker *checker, int *counter)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(checker == 0,
+ PROGRESS_CHECKER_INVALID_OBJECT);
+ }
+
+ if (checker->failed == 0) {
+ *counter = -1;
+ return 0;
+ }
+
+ *counter = bit_vector_find_first_set(checker->failure);
+ bit_vector_clear(checker->failure, *counter);
+ checker->failed--;
+
+ return 0;
+}
+
+
+/// A standard way to print the results of a progress check failure, suitable
+/// for use as a ProgressChecker callback.
+///
+/// \param checker The checker - which may or may not have failed. If the
+/// checker did fail, then a failure report is printed using printk().
+///
+/// \param arg The value to return in case of failure. In case of
+/// success, 0 is returned.
+///
+/// \param failed - The number of failed checks
+
+int
+progress_checker_printk(ProgressChecker *checker,
+ void *arg,
+ size_t failed)
+{
+ int counter;
+
+ if (!failed) {
+ return 0;
+ }
+
+ printk("---------------------------------------------------------------\n");
+ printk("-- Progress check failed for \"%s\" (%p).\n",
+ checker->name, checker);
+ printk("-- Check %zu over interval 0x%016llx - 0x%016llx\n",
+ checker->checks, checker->start_check, checker->end_check);
+ printk("-- %zu failed counter%s listed below\n",
+ failed, failed > 1 ? "s are" : " is");
+ printk("---------------------------------------------------------------\n");
+
+ do {
+ progress_checker_next_failure(checker, &counter);
+ if (counter < 0) {
+ break;
+ }
+ printk("%4d. 0x%016llx\n", counter, checker->pass_counts[counter]);
+ } while (1);
+
+ printk("---------------------------------------------------------------\n");
+
+ return (int)arg;
+}
+
+
+/// Call progress_checker_printk(), then create a kernel dump on failure
+///
+/// \param checker The checker - which may or may not have failed. If the
+/// checker did fail, then a failure report is printed using
+/// progress_checker_printk().
+///
+/// \param arg The value to return in case of failure. In case of
+/// success, 0 is returned.
+///
+/// \param failed - The number of failed checks
+///
+/// If progress_checker_printk() fails with a non-0 return code then this API
+/// prints a full SSX kernel dump after the progress_checker_printk() report.
+int
+progress_checker_printk_dump(ProgressChecker *checker,
+ void *arg,
+ size_t failed)
+{
+ int rc;
+ SsxMachineContext ctx;
+
+ rc = progress_checker_printk(checker, arg, failed);
+ if (rc != 0) {
+ ssx_critical_section_enter(SSX_CRITICAL, &ctx);
+ ssx_dump(ssxout, 0);
+ ssx_critical_section_exit(&ctx);
+ }
+
+ return rc;
+}
+
+
+/// Dump a progress checker structure using printk()
+
+void
+progress_checker_dump(ProgressChecker *checker)
+{
+ size_t i;
+
+ printk("Dump of progress checker \"%s\" (%p)\n"
+ " Counters = %zu\n"
+ " Checks = %zu\n"
+ " Failed = %zu\n"
+ " Callback = %p(%p)\n",
+ checker->name, checker, checker->counters, checker->checks,
+ checker->failed, checker->callback, checker->arg);
+
+ printk(" Pass Counts (%p) :\n", checker->pass_counts);
+ for (i = 0; i < checker->counters; i++) {
+ printk(" %9d%c 0x%016llx\n",
+ i,
+ bit_vector_is_set(checker->exempt, i) ? '*' : ' ',
+ checker->pass_counts[i]);
+ }
+ printk(" Saved Counts (%p) :\n", checker->saved_counts);
+ for (i = 0; i < checker->counters; i++) {
+ printk(" %9d 0x%016llx\n",
+ i, checker->saved_counts[i]);
+ }
+}
+
+
+
+
+
+
+
+
diff --git a/src/lib/ppc405lib/progress.h b/src/lib/ppc405lib/progress.h
new file mode 100644
index 0000000..3454a0f
--- /dev/null
+++ b/src/lib/ppc405lib/progress.h
@@ -0,0 +1,177 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/progress.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __PROGRESS_H__
+#define __PROGRESS_H__
+
+// $Id$
+
+/// \file progress.h
+/// \brief Programmable progress (hang) checking
+
+#include <time.h>
+#include "ssx.h"
+#include "byte_pool.h"
+#include "ssx_io.h"
+
+#ifndef __ASSEMBLER__
+
+struct ProgressChecker;
+
+/// ProgressChecker callback type
+///
+/// \param checker The checker that has just been checked
+///
+/// \param arg The private argument provided when the checker was created
+///
+/// \param failed The number of failed pass counts - 0 indicates no failures
+
+typedef int (*ProgressCheckerCallback)(struct ProgressChecker* checker,
+ void* arg,
+ size_t failed);
+
+
+/// A simple progress (hang) checker. For API details see file progress.c
+
+typedef struct ProgressChecker {
+
+ /// The application provided pass-count array
+ uint64_t *pass_counts;
+
+ /// The number of pass-count counters in the array.
+ size_t counters;
+
+ /// The (optional) name of the checker for reporting purposes.
+ const char *name;
+
+ /// The (optional) checker callback.
+ ProgressCheckerCallback callback;
+
+ /// The checker callback private argument
+ void *arg;
+
+ /// The dynamically-allocated saved pass counts.
+ uint64_t *saved_counts;
+
+ /// The dynamically-allocated exemption bit-vector
+ ///
+ /// \todo Get or implement a generic unlimited-precision bit vector
+ uint8_t *exempt;
+
+ /// The dynamically-allocated failure bit-vector
+ uint8_t *failure;
+
+ /// The number of bytes in the bit vector
+ size_t bit_vector_bytes;
+
+ /// Defer all checking the next time progress_checker_check() is called.
+ ///
+ /// See progress_checker_require_defer()
+ int defer;
+
+ /// The number of failures present in the *failure vector
+ size_t failed;
+
+ /// A timer object to support time-based checking.
+ SsxTimer timer;
+
+ /// The number of times progress_checker_check() has been called on the
+ /// object.
+ size_t checks;
+
+ /// The time the last check started
+ SsxTimebase start_check;
+
+ /// The time the last check ended
+ SsxTimebase end_check;
+
+} ProgressChecker;
+
+
+int
+progress_checker_create(ProgressChecker *checker,
+ const char *name,
+ uint64_t *pass_counts,
+ size_t counters,
+ ProgressCheckerCallback callback,
+ void *arg);
+
+int
+progress_checker_exempt(ProgressChecker *checker,
+ size_t counter);
+
+int
+progress_checker_exempt_all(ProgressChecker *checker);
+
+int
+progress_checker_require(ProgressChecker *checker,
+ size_t counter);
+
+int
+progress_checker_require_defer(ProgressChecker *checker,
+ size_t counter);
+
+int
+progress_checker_check(ProgressChecker *checker);
+
+int
+progress_checker_schedule(ProgressChecker *checker,
+ SsxInterval interval,
+ SsxInterval period);
+
+int
+progress_checker_cancel(ProgressChecker *checker);
+
+int
+progress_checker_next_failure(ProgressChecker *checker, int *counter);
+
+int
+progress_checker_delete(ProgressChecker *checker);
+
+int
+progress_checker_printk(ProgressChecker *checker,
+ void *arg,
+ size_t failed);
+
+int
+progress_checker_printk_dump(ProgressChecker *checker,
+ void *arg,
+ size_t failed);
+
+void
+progress_checker_dump(ProgressChecker *checker);
+
+
+#endif /* __ASSEMBLER__ */
+
+// Error/Panic codes
+
+#define PROGRESS_CHECKER_INVALID_OBJECT 0x00776001
+#define PROGRESS_CHECKER_INVALID_ARGUMENT 0x00776002
+#define PROGRESS_CHECKER_FAILED 0x00776003
+#define PROGRESS_CHECKER_CALLBACK_PANIC 0x00776004
+#define PROGRESS_CHECKER_INVARIANT 0x00776005
+#define PROGRESS_CHECKER_ALLOCATION_FAILED 0x00776006
+
+#endif /* __PROGRESS_H__ */
diff --git a/src/lib/ppc405lib/puts.c b/src/lib/ppc405lib/puts.c
new file mode 100644
index 0000000..446671a
--- /dev/null
+++ b/src/lib/ppc405lib/puts.c
@@ -0,0 +1,119 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/puts.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: puts.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/puts.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file puts.c
+/// \brief Implementation of puts(), fputs(), putchar(), fputc()
+///
+/// The implementations of these APIs are split out to save code space for
+/// applications that do not require them.
+
+#include "ssx_io.h"
+
+
+/// Put a character to a stream
+///
+/// The fputc() function writes the byte specified by \a c (converted to an
+/// unsigned char) to the stream pointed to by \a stream. On success, fputc()
+/// returns the value written, i.e., the \c unsigned \c char form of \a c.
+///
+/// The POSIX standard fputc() returns EOF on error; this version returns the
+/// negative error code of the underlying I/O error, which will also be set in
+/// the \a error field of the \a stream. Note that SSX may also be configured
+/// to panic in the event of an I/O error.
+
+int
+fputc(int c, FILE *stream)
+{
+ unsigned char uc = (unsigned char)c;
+ int rc = swrite(stream, (void *)(&uc), 1, 0);
+ if (rc < 0) {
+ return rc;
+ } else {
+ return uc;
+ }
+}
+
+
+/// Put a string to a stream
+///
+/// The fputs() function writes the null-terminated string \a s to the stream
+/// pointed to by \a stream. The terminating null byte is not written. On
+/// success, fputs() returns 0.
+///
+/// The POSIX standard fputc() returns EOF on error; this version returns the
+/// negative error code of the underlying I/O error, which will also be set in
+/// the \a error field of the \a stream. Note that SSX may also be configured
+/// to panic in the event of an I/O error.
+
+int
+fputs(const char *s, FILE *stream)
+{
+ return swrite(stream, s, strlen(s), 0);
+}
+
+/// Put a string to \c stdout
+///
+/// The puts() function writes the null-terminated string \a s followed by a
+/// newline to \a stdout. The terminating null byte is not written. On
+/// success, puts() returns 0.
+///
+/// The POSIX standard fputc() returns EOF on error; this version returns the
+/// negative error code of the underlying I/O error, which will also be set in
+/// the \a error field of the \a stream. Note that SSX may also be configured
+/// to panic in the event of an I/O error.
+
+int
+puts(const char *s)
+{
+ int rc = fputs(s, stdout);
+ if (rc < 0) {
+ return rc;
+ } else {
+ rc = fputc('\n', stdout);
+ if (rc < 0) {
+ return rc;
+ } else {
+ return 0;
+ }
+ }
+}
+
+
+/// Put a character to \a stdout.
+///
+/// \c putchar(c) is equivalent to <c> fputc(c, stdout) </c>.
+
+int
+putchar(int c)
+{
+ return fputc(c, stdout);
+}
diff --git a/src/lib/ppc405lib/rtx_stdio.c b/src/lib/ppc405lib/rtx_stdio.c
new file mode 100644
index 0000000..4bb1a18
--- /dev/null
+++ b/src/lib/ppc405lib/rtx_stdio.c
@@ -0,0 +1,149 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/rtx_stdio.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id$
+
+/// \file rtx_stdio.c
+/// \brief SSX I/O drivers for RTX stdio streams
+///
+/// The RTX \a stdout and \a stderr components accept 1, 2 and 4-byte
+/// transactions on a 32-bit OCI address and write the data to the RTX
+/// job's \a stdout or \a stderr respectively. The \a stdin device is not yet
+/// implemented.
+
+#include "ssx.h"
+#include "rtx_stdio.h"
+
+RtxStdio rtx_stdin;
+RtxStdio rtx_stdout;
+RtxStdio rtx_stderr;
+
+int
+rtx_stdio_sread(FILE *stream, void *buf, size_t count, size_t *read)
+{
+ SSX_PANIC(ENXIO);
+ return -ENXIO;
+}
+
+
+int
+rtx_stdio_swrite(FILE *stream, const void *buf,
+ size_t count, size_t *written)
+{
+ RtxStdio *rtx = (RtxStdio *)stream;
+ size_t n;
+
+ n = count;
+ while (n) {
+ if (n >= 4) {
+ out32(rtx->address, *((uint32_t *)buf));
+ buf += 4;
+ n -= 4;
+ } else if (n >= 2) {
+ out16(rtx->address, *((uint16_t *)buf));
+ buf += 2;
+ n -= 2;
+ } else {
+ out8(rtx->address, *((uint8_t *)buf));
+ buf++;
+ n--;
+ }
+ }
+
+ if (written != 0) {
+ *written = count;
+ }
+
+ return 0;
+}
+
+
+ssize_t
+rtx_stdio_fflush(FILE *stream)
+{
+ RtxStdio *rtx = (RtxStdio *)stream;
+
+ out8(rtx->flush_address, 0);
+ return 0;
+}
+
+
+int
+rtx_stdin_create(RtxStdio *stream)
+{
+ FILE *base = (FILE *)stream;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(stream == 0, EBADF);
+ }
+
+ memset((void *)stream, 0, sizeof(RtxStdio));
+ base->sread = rtx_stdio_sread;
+
+ stream->address = RTX_STDIN;
+
+ return 0;
+}
+
+
+int
+rtx_stdout_create(RtxStdio *stream)
+{
+ FILE *base = (FILE *)stream;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(stream == 0, EBADF);
+ }
+
+ memset((void *)stream, 0, sizeof(RtxStdio));
+ base->swrite = rtx_stdio_swrite;
+ base->fflush = rtx_stdio_fflush;
+
+ stream->address = RTX_STDOUT;
+ stream->flush_address = RTX_STDOUT_FLUSH;
+
+ return 0;
+}
+
+
+int
+rtx_stderr_create(RtxStdio *stream)
+{
+ FILE *base = (FILE *)stream;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(stream == 0, ENXIO);
+ }
+
+ memset((void *)stream, 0, sizeof(RtxStdio));
+ base->swrite = rtx_stdio_swrite;
+ base->fflush = rtx_stdio_fflush;
+
+ stream->address = RTX_STDERR;
+ stream->flush_address = RTX_STDERR_FLUSH;
+
+ return 0;
+}
+
+
diff --git a/src/lib/ppc405lib/rtx_stdio.h b/src/lib/ppc405lib/rtx_stdio.h
new file mode 100644
index 0000000..cd2a439
--- /dev/null
+++ b/src/lib/ppc405lib/rtx_stdio.h
@@ -0,0 +1,74 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/rtx_stdio.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __RTX_STDIO_H__
+#define __RTX_STDIO_H__
+
+// $Id$
+
+/// \file rtx_stdio.h
+/// \brief SSX I/O implementations for RTX stdio streams
+
+#include "ssx_io.h"
+#include "rtx_stdio_addresses.h"
+
+/// A FILE structure for a RTX fake stdio stream
+
+typedef struct {
+
+ /// The base class
+ FILE stream;
+
+ /// The MMIO address of the RTX device for the stream
+ SsxAddress address;
+
+ /// The MMIO address of the RTX device for flushing the stream;
+ SsxAddress flush_address;
+
+} RtxStdio;
+
+extern RtxStdio rtx_stdin;
+extern RtxStdio rtx_stdout;
+extern RtxStdio rtx_stderr;
+
+int
+rtx_stdin_create(RtxStdio *stream);
+
+int
+rtx_stdout_create(RtxStdio *stream);
+
+int
+rtx_stderr_create(RtxStdio *stream);
+
+int
+rtx_stdio_sread(FILE *stream, void *buf, size_t count, size_t *read);
+
+int
+rtx_stdio_swrite(FILE *stream, const void *buf,
+ size_t count, size_t *written);
+
+int
+rtx_stdio_sflush(FILE *stream);
+
+#endif /* __RTX_STDIO_H__ */
diff --git a/src/lib/ppc405lib/rtx_stdio_addresses.h b/src/lib/ppc405lib/rtx_stdio_addresses.h
new file mode 100644
index 0000000..5359f7f
--- /dev/null
+++ b/src/lib/ppc405lib/rtx_stdio_addresses.h
@@ -0,0 +1,55 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/rtx_stdio_addresses.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __RTX_STDIO_ADDRESSES_H__
+#define __RTX_STDIO_ADDRESSES_H__
+
+// $Id$
+
+/// \file rtx_stdio_addresses.h
+/// \brief MMIO addresses and offsets of the rtx fake stdio model
+///
+/// The RTX stdio module appears as OCI device #7? Reading 1 byte from the
+/// stdin offset returns that byte from stdin. Writing 1, 2 or 4 bytes to the
+/// stdout or stderr offsets causes output on that stream. Writing any single
+/// byte to the 'flush' offsets flush the stdout or stderr streams.
+///
+/// -*- This header is maintained as part of the PMX RTX model. -*-
+/// -*- Do not edit in the SSX library as your edits will be lost. -*-
+
+#define RTX_STDIO_BASE 0x40060000
+
+#define RTX_STDIN_OFFSET 0x00
+#define RTX_STDOUT_OFFSET 0x04
+#define RTX_STDOUT_FLUSH_OFFSET 0x08
+#define RTX_STDERR_OFFSET 0x0c
+#define RTX_STDERR_FLUSH_OFFSET 0x10
+
+#define RTX_STDIN (RTX_STDIO_BASE + RTX_STDIN_OFFSET)
+#define RTX_STDOUT (RTX_STDIO_BASE + RTX_STDOUT_OFFSET)
+#define RTX_STDOUT_FLUSH (RTX_STDIO_BASE + RTX_STDOUT_FLUSH_OFFSET)
+#define RTX_STDERR (RTX_STDIO_BASE + RTX_STDERR_OFFSET)
+#define RTX_STDERR_FLUSH (RTX_STDIO_BASE + RTX_STDERR_FLUSH_OFFSET)
+
+#endif /* __RTX_STDIO_ADDRESSES_H__ */
diff --git a/src/lib/ppc405lib/simics_stdio.c b/src/lib/ppc405lib/simics_stdio.c
new file mode 100644
index 0000000..6ff1fa9
--- /dev/null
+++ b/src/lib/ppc405lib/simics_stdio.c
@@ -0,0 +1,174 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/simics_stdio.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: simics_stdio.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/simics_stdio.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file simics_stdio.c
+/// \brief SSX I/O drivers for Simics stdio streams
+///
+/// The Simics 'stdio' component is a pseudo serial port for I/O to stdio,
+/// stdout and stderr, as well as to other configurable streams. Each virtual
+/// file potentially has a read port, write port and flush port.
+///
+/// The write ports accept 1, 2 and 4-byte transactions on a 32-bit OCI
+/// address and write the data to the associated stream. Writing any value to
+/// the flush port flushes the output stream. The input ports are not yet
+/// implemented.
+
+#include "ssx.h"
+#include "simics_stdio.h"
+
+
+SimicsStdio simics_stdin;
+SimicsStdio simics_stdout;
+SimicsStdio simics_stderr;
+
+int
+simics_stdio_sread(FILE *stream, void *buf, size_t count, size_t *read)
+{
+ SSX_PANIC(ENXIO);
+ return -ENXIO;
+}
+
+
+int
+simics_stdio_swrite(FILE *stream, const void *buf,
+ size_t count, size_t *written)
+{
+ SimicsStdio *simics = (SimicsStdio *)stream;
+ size_t n;
+
+ n = count;
+ while (n) {
+ if (n >= 4) {
+ out32(simics->write_address, *((uint32_t *)buf));
+ buf += 4;
+ n -= 4;
+ } else if (n >= 2) {
+ out16(simics->write_address, *((uint16_t *)buf));
+ buf += 2;
+ n -= 2;
+ } else {
+ out8(simics->write_address, *((uint8_t *)buf));
+ buf++;
+ n--;
+ }
+ }
+
+ *written = count;
+
+ return 0;
+}
+
+
+ssize_t
+simics_stdio_fflush(FILE *stream)
+{
+ SimicsStdio *simics = (SimicsStdio *)stream;
+
+ out8(simics->flush_address, 0);
+ return 0;
+}
+
+
+/// Create a SimicsStdio stream
+///
+/// Any of the \a read_address, \a write_address or \a flush_address which are
+/// non-0 specify that the stream supports the associated method. The Simics
+/// I/O drivers do not require locking.
+
+int
+simics_stdio_create(SimicsStdio* stream,
+ SsxAddress read_address,
+ SsxAddress write_address,
+ SsxAddress flush_address)
+{
+ FILE *base = (FILE *)stream;
+ int rc;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(stream == 0, EBADF);
+ }
+
+ rc = FILE_create((FILE*)stream, 0);
+
+ if (!rc) {
+
+ stream->read_address = read_address;
+ if (read_address != 0) {
+ base->sread = simics_stdio_sread;
+ }
+
+ stream->write_address = write_address;
+ if (write_address != 0) {
+ base->swrite = simics_stdio_swrite;
+ }
+
+ stream->flush_address = flush_address;
+ if (flush_address != 0) {
+ base->fflush = simics_stdio_fflush;
+ }
+ }
+
+ return rc;
+}
+
+
+int
+simics_stdin_create(SimicsStdio *stream)
+{
+ return simics_stdio_create(stream, SIMICS_STDIN, 0, 0);
+}
+
+
+int
+simics_stdout_create(SimicsStdio *stream)
+{
+ return simics_stdio_create(stream, 0, SIMICS_STDOUT, SIMICS_STDOUT_FLUSH);
+}
+
+int
+simics_stderr_create(SimicsStdio *stream)
+{
+ return simics_stdio_create(stream, 0, SIMICS_STDERR, SIMICS_STDERR_FLUSH);
+}
+
+int
+simics_stdfile_create(SimicsStdio *stream, int fn)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF((fn < 0) > (fn >= SIMICS_STDFILE_STREAMS), EBADF);
+ }
+
+ return simics_stdio_create(stream,
+ SIMICS_STDFILE_READ(fn),
+ SIMICS_STDFILE_WRITE(fn),
+ SIMICS_STDFILE_FLUSH(fn));
+}
diff --git a/src/lib/ppc405lib/simics_stdio.h b/src/lib/ppc405lib/simics_stdio.h
new file mode 100644
index 0000000..b9ebfcf
--- /dev/null
+++ b/src/lib/ppc405lib/simics_stdio.h
@@ -0,0 +1,93 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/simics_stdio.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __SIMICS_STDIO_H__
+#define __SIMICS_STDIO_H__
+
+// $Id: simics_stdio.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/simics_stdio.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file simics_stdio.h
+/// \brief SSX I/O implementations for Simics stdio streams
+
+#include "ssx_io.h"
+#include "simics_stdio_addresses.h"
+#include "string.h"
+
+/// A FILE structure for a Simics fake stdio stream
+
+typedef struct {
+
+ /// The base class
+ FILE stream;
+
+ /// The MMIO address of the Simics read port for the stream
+ SsxAddress read_address;
+
+ /// The MMIO address of the Simics write port for the stream
+ SsxAddress write_address;
+
+ /// The MMIO address of the Simics device for flushing the stream;
+ SsxAddress flush_address;
+
+} SimicsStdio;
+
+extern SimicsStdio simics_stdin;
+extern SimicsStdio simics_stdout;
+extern SimicsStdio simics_stderr;
+
+int
+simics_stdio_create(SimicsStdio* stream,
+ SsxAddress read_address,
+ SsxAddress write_address,
+ SsxAddress flush_address);
+
+int
+simics_stdin_create(SimicsStdio *stream);
+
+int
+simics_stdout_create(SimicsStdio *stream);
+
+int
+simics_stderr_create(SimicsStdio *stream);
+
+int
+simics_stdfile_create(SimicsStdio *stream, int fn);
+
+int
+simics_stdio_sread(FILE *stream, void *buf, size_t count, size_t *read);
+
+int
+simics_stdio_swrite(FILE *stream, const void *buf,
+ size_t count, size_t *written);
+
+int
+simics_stdio_sflush(FILE *stream);
+
+#endif /* __SIMICS_STDIO_H__ */
diff --git a/src/lib/ppc405lib/simics_stdio_addresses.h b/src/lib/ppc405lib/simics_stdio_addresses.h
new file mode 100644
index 0000000..4554bbf
--- /dev/null
+++ b/src/lib/ppc405lib/simics_stdio_addresses.h
@@ -0,0 +1,91 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/simics_stdio_addresses.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __SIMICS_STDIO_ADDRESSES_H__
+#define __SIMICS_STDIO_ADDRESSES_H__
+
+// $Id: simics_stdio_addresses.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/simics_stdio_addresses.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file simics_stdio_adresses.h
+/// \brief MMIO addresses and offsets of the Simics fake stdio model
+///
+/// The Simics 'stdio' component is a pseudo serial port for I/O to stdio,
+/// stdout and stderr, as well as to other configurable streams. Each virtual
+/// file potentially has a read port, write port and flush port.
+///
+/// The write ports accept 1, 2 and 4-byte transactions on a 32-bit OCI
+/// address and write the data to the associated stream. Writing any value to
+/// the flush port flushes the output stream. The input ports are not yet
+/// implemented.
+
+// -*- This header is maintained as part of the PMX Simics model. -*-
+// -*- Do not edit in the SSX library as your edits will be lost. -*-
+
+#define SIMICS_STDIO_BASE 0x40060000
+
+#define SIMICS_STDIN_OFFSET 0x00
+#define SIMICS_STDOUT_OFFSET 0x04
+#define SIMICS_STDOUT_FLUSH_OFFSET 0x08
+#define SIMICS_STDERR_OFFSET 0x0c
+#define SIMICS_STDERR_FLUSH_OFFSET 0x10
+
+#define SIMICS_STDFILE_0_OFFSET 0x14
+#define SIMICS_STDFILE_1_OFFSET 0x20
+#define SIMICS_STDFILE_2_OFFSET 0x2c
+#define SIMICS_STDFILE_3_OFFSET 0x38
+
+#define SIMICS_STDFILE_STREAMS 4
+
+#define SIMICS_STDIN (SIMICS_STDIO_BASE + SIMICS_STDIN_OFFSET)
+#define SIMICS_STDOUT (SIMICS_STDIO_BASE + SIMICS_STDOUT_OFFSET)
+#define SIMICS_STDOUT_FLUSH (SIMICS_STDIO_BASE + SIMICS_STDOUT_FLUSH_OFFSET)
+#define SIMICS_STDERR (SIMICS_STDIO_BASE + SIMICS_STDERR_OFFSET)
+#define SIMICS_STDERR_FLUSH (SIMICS_STDIO_BASE + SIMICS_STDERR_FLUSH_OFFSET)
+
+#define SIMICS_STDFILE_READ_OFFSET(fn) \
+ (SIMICS_STDFILE_0_OFFSET + (12 * fn) + 0x00)
+
+#define SIMICS_STDFILE_WRITE_OFFSET(fn) \
+ (SIMICS_STDFILE_0_OFFSET + (12 * fn) + 0x04)
+
+#define SIMICS_STDFILE_FLUSH_OFFSET(fn) \
+ (SIMICS_STDFILE_0_OFFSET + (12 * fn) + 0x08)
+
+#define SIMICS_STDFILE_READ(fn) \
+ (SIMICS_STDIO_BASE + SIMICS_STDFILE_READ_OFFSET(fn))
+
+#define SIMICS_STDFILE_WRITE(fn) \
+ (SIMICS_STDIO_BASE + SIMICS_STDFILE_WRITE_OFFSET(fn))
+
+#define SIMICS_STDFILE_FLUSH(fn) \
+ (SIMICS_STDIO_BASE + SIMICS_STDFILE_FLUSH_OFFSET(fn))
+
+
+#endif /* __SIMICS_STDIO_ADDRESSES_H__ */
diff --git a/src/lib/ppc405lib/sprintf.c b/src/lib/ppc405lib/sprintf.c
new file mode 100644
index 0000000..0a95416
--- /dev/null
+++ b/src/lib/ppc405lib/sprintf.c
@@ -0,0 +1,136 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/sprintf.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: sprintf.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/sprintf.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file sprintf.c \brief Implementations of sprintf() and snprintf() using
+/// StringStream.
+
+#include "ssx.h"
+#include "ssx_io.h"
+#include "string_stream.h"
+
+
+// sprintf() is easy - just blindly copy in the data.
+
+static int
+sprintf_swrite(FILE *stream, const void *buf, size_t size, size_t *written)
+{
+ StringStream *string = (StringStream *)stream;
+
+ memcpy((void *)(&(string->data[string->next_write])), buf, size);
+ string->next_write += size;
+ *written = size;
+ return 0;
+}
+
+
+// snprintf() requires that bytes that won't fit in the array are simply
+// discarded, but still accounted for. Note that vfprintf() is doing the
+// high-level accounting.
+
+static int
+snprintf_swrite(FILE *stream, const void *buf, size_t size, size_t *written)
+{
+ StringStream *string = (StringStream *)stream;
+
+ size_t to_write = MIN(size, string->size - string->next_write - 1);
+
+ memcpy((void *)(&(string->data[string->next_write])), buf, to_write);
+ string->next_write += to_write;
+ *written = size;
+ return 0;
+}
+
+
+// We use a StringStream to implement [v]sprintf() and [v]snprintf(). Once
+// the formatting is finished the NULL terminator is added.
+
+int
+vsprintf(char *str, const char *format, va_list argp)
+{
+ ssize_t rc;
+ StringStream stream;
+
+ _string_stream_create(&stream, str, 1, 0, sprintf_swrite);
+ rc = vfprintf((FILE *)(&stream), format, argp);
+ stream.data[stream.next_write] = 0;
+ return rc;
+}
+
+
+
+int
+sprintf(char *str, const char *format, ...)
+{
+ va_list argp;
+ ssize_t rc;
+
+ va_start(argp, format);
+ rc = vsprintf(str, format, argp);
+ va_end(argp);
+
+ return rc;
+}
+
+
+int
+vsnprintf(char *str, size_t size, const char *format, va_list argp)
+{
+ ssize_t rc;
+ StringStream stream;
+
+ if (size == 0) {
+ return 0;
+ }
+
+ _string_stream_create(&stream, str, size, 0, snprintf_swrite);
+ rc = vfprintf((FILE *)(&stream), format, argp);
+ stream.data[stream.next_write] = 0;
+ return rc;
+}
+
+
+int
+snprintf(char *str, size_t size, const char *format, ...)
+{
+ va_list argp;
+ ssize_t rc;
+
+ if (size == 0) {
+ return 0;
+ }
+
+ va_start(argp, format);
+ rc = vsnprintf(str, size, format, argp);
+ va_end(argp);
+
+ return rc;
+}
diff --git a/src/lib/ppc405lib/ssx_dump.c b/src/lib/ppc405lib/ssx_dump.c
new file mode 100644
index 0000000..52334ab
--- /dev/null
+++ b/src/lib/ppc405lib/ssx_dump.c
@@ -0,0 +1,233 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/ssx_dump.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: ssx_dump.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/ssx_dump.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ssx_dump.c
+/// \brief Routines for dumping SSX kernel data structures
+///
+/// \note This is a quick hack to help solve a P8 bringup issue. This code is
+/// PPC405 (OCC) specific, i.e., not "portable" SSX. Ideally this type of dump
+/// would be implemented in an external debugging tool as well, however it's
+/// simplest to implement here in the execution context.
+
+#include "ssx_dump.h"
+
+#define SSX_DUMP_UNIMPLEMENTED 0x00d86701
+
+static const char* _threadState[] = {
+ 0,
+ "Suspended Runnable",
+ "Mapped",
+ "Suspended Blocked",
+ "Completed",
+ "Deleted",
+};
+
+static const char* _threadFlags[] = {
+ 0,
+ "Semaphore Pend",
+ "Timer Pend",
+ "Timer Pend | Semaphore Pend",
+ "Timed Out",
+ "Timed Out | Semaphore Pend",
+ "Timed Out | Timer Pend",
+ "Timed Out | Timer Pend | Semaphore Pend",
+};
+
+
+static void
+_dumpTimer(FILE* stream, SsxTimer* timer)
+{
+ fprintf(stream,
+ "-- Timer @ %p\n"
+ "-- Deque.previous = %p\n"
+ "-- Deque.next = %p\n"
+ "-- Timeout = 0x%016llx\n"
+ "-- Period = 0x%016llx\n"
+ "-- Callback = %p\n"
+ "-- Arg = %p\n"
+ "-- Options = 0x%02x\n",
+ timer,
+ timer->deque.previous,
+ timer->deque.next,
+ timer->timeout,
+ (unsigned long long)(timer->period),
+ timer->callback,
+ timer->arg,
+ timer->options);
+}
+
+
+static void
+_dumpThread(FILE* stream, SsxThread* thread)
+{
+ SsxThreadContext* threadCtx;
+ SsxThreadContextFullIrq* threadCtxIrq;
+ uint32_t srr[4], lr, sp;
+
+ fprintf(stream,
+ "-- Thread mapped at priority %d (%p)\n"
+ "-- Thread state = %s (%d)\n"
+ "-- Thread flags = %s (0x%02x)\n"
+ "-- Saved Stack Pointer = %p\n",
+ thread->priority, thread,
+ _threadState[thread->state], thread->state,
+ _threadFlags[thread->flags], thread->flags,
+ (void*)thread->saved_stack_pointer);
+
+ if (thread->flags & SSX_THREAD_FLAG_SEMAPHORE_PEND) {
+
+ fprintf(stream,
+ "-- Semaphore = %p\n",
+ (void*)thread->semaphore);
+ }
+ fprintf(stream,
+ "---------------------------------------------\n");
+
+ if (thread->flags & SSX_THREAD_FLAG_TIMER_PEND) {
+
+ _dumpTimer(stream, &(thread->timer));
+ fprintf(stream,
+ "---------------------------------------------\n");
+ }
+
+ if ((thread == ssx_current()) && !__ssx_kernel_context_any_interrupt()) {
+
+ fprintf(stream,
+ "-- This thread is executing ssx_dump()\n");
+
+ } else {
+
+ if (thread == ssx_current()) {
+
+ // This is the interrupted thread, and only has its volatile
+ // context saved. The thread stack pointer is stored in a global
+ // kernel variable.
+
+ if (__ssx_kernel_context_critical_interrupt()) {
+
+ SSX_PANIC(SSX_DUMP_UNIMPLEMENTED);
+ srr[0] = srr[1] = srr[2] = srr[3] = lr = sp = 0; /* For GCC */
+
+ } else {
+
+ threadCtxIrq =
+ (SsxThreadContextFullIrq*)__ssx_saved_sp_noncritical;
+ srr[0] = threadCtxIrq->srr0;
+ srr[1] = threadCtxIrq->srr1;
+ srr[2] = threadCtxIrq->srr2;
+ srr[3] = threadCtxIrq->srr3;
+ lr = threadCtxIrq->lr;
+ sp = threadCtxIrq->r1;
+ }
+ } else {
+
+ // This is a fully swapped-out thread. The context is saved in
+ // at the stored stack pointer.
+
+ threadCtx = (SsxThreadContext*)(thread->saved_stack_pointer);
+ srr[0] = threadCtx->srr0;
+ srr[1] = threadCtx->srr1;
+ srr[2] = threadCtx->srr2;
+ srr[3] = threadCtx->srr3;
+ lr = threadCtx->lr;
+ sp = ((uint32_t*)threadCtx->r1)[0];
+ }
+
+ fprintf(stream,
+ "-- SRR0: 0x%08x SRR1: 0x%08x "
+ "SRR2: 0x%08x SRR3: 0x%08x\n"
+ "-- LR: 0x%08x\n",
+ srr[0], srr[1], srr[2], srr[3],
+ lr);
+
+ fprintf(stream,
+ "---------------------------------------------\n");
+
+ // Unwind the stack
+
+ while (sp != 0) {
+
+ fprintf(stream,
+ "-- SP: 0x%08x *LR*:0x%08x\n",
+ sp, ((uint32_t*)sp)[1]);
+ sp = ((uint32_t*)sp)[0];
+ }
+ }
+}
+
+
+
+
+void
+ssx_dump(FILE* stream, int options)
+{
+ int i, sep;
+ SsxThread* thread;
+
+ fprintf(stream,
+ "------------------------------------------------------------\n");
+ fprintf(stream,
+ "-- SSX Kernel Dump @ 0x%016llx\n"
+ "-- USPRG0 = 0x%08x\n"
+ "-- __ssx_run_queue = 0x%08x\n",
+ ssx_timebase_get(),
+ mfspr(SPRN_USPRG0),
+ __ssx_run_queue);
+ fprintf(stream,
+ "------------------------------------------------------------\n");
+
+ sep = 0;
+
+ for (i = 0; i < SSX_THREADS; i++) {
+
+ ssx_thread_at_priority(i, &thread);
+ if (thread) {
+ if (sep) {
+ fprintf(stream,
+ "*********************************************\n");
+ }
+ _dumpThread(stream, thread);
+ sep = 1;
+ }
+ }
+
+ fprintf(stream,
+ "------------------------------------------------------------\n");
+}
+
+
+
+
+
+
+
+
diff --git a/src/lib/ppc405lib/ssx_dump.h b/src/lib/ppc405lib/ssx_dump.h
new file mode 100644
index 0000000..a413214
--- /dev/null
+++ b/src/lib/ppc405lib/ssx_dump.h
@@ -0,0 +1,82 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/ssx_dump.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __SSX_DUMP_H__
+#define __SSX_DUMP_H__
+
+// $Id: ssx_dump.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/ssx_dump.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ssx_dump.h
+/// \brief Routines for dumping SSX kernel data structures
+
+#include "ssx.h"
+
+/// \defgroup ssx_dump_options Options for ssx_dump()
+///
+/// No options are currently specified.
+///
+/// @{
+
+/// @}
+
+#ifndef __ASSEMBLER__
+
+/// Dump the kernel state
+///
+/// \param i_stream The stream to receive the dump. If the dump is being
+/// generated prior to a kernel panic then this would typically be \a ssxout,
+/// the stream used by printk.
+///
+/// \param i_options AN OR-mask of option flags; See \ref ssx_dump_options
+///
+/// The SSX kernel dump produces a formatted snapshot of the state of the
+/// kernel and the mapped threads. This API does not manipulate the machine
+/// context; If it is required to produce a precise snapshot then the caller
+/// will need to make the call from a critical section.
+///
+/// The following information is standard in the dump
+///
+/// - The interrupt and thread state of the kernel
+/// - The state of each thread
+/// - A stack trace for each thread
+///
+/// Options : TBD
+///
+/// \bug There are likely several bugs in the current implementation due to
+/// the assumption that the code is being called from a state in which the
+/// kernel context is not changing. We don't have time to code and test the
+/// most general implementation now. To guarantee correct operation the API
+/// must currently be called from an SSX_CRITICAL critical section.
+void
+ssx_dump(FILE* stream, int options);
+
+#endif // __ASSEMBLER__
+
+#endif // __SSX_DUMP_H__
diff --git a/src/lib/ppc405lib/ssx_io.c b/src/lib/ppc405lib/ssx_io.c
new file mode 100644
index 0000000..b517aeb
--- /dev/null
+++ b/src/lib/ppc405lib/ssx_io.c
@@ -0,0 +1,335 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/ssx_io.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: ssx_io.c,v 1.2 2014/02/03 01:30:25 daviddu Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/ssx_io.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ssx_io.c
+/// \brief SSX analog-replacement for C \<stdio.h\> and \<unistd.h\> functions
+///
+/// The SSX library provides simple analogs for I/O functions found in the
+/// typical C libraries and Posix standards. I/O is not considered part of the
+/// SSX kernel per-se - I/O is implemented by the application creating I/O
+/// abstractions and drivers using the simple SSX kernel services. [However,
+/// the ssx_io library does provide a printk() function for use by kernel
+/// drivers, so the lines are not completely clear.]
+///
+/// This library provides a FILE structure or 'base class' to represent a
+/// character stream. Abstractions for different devices will 'derive' a
+/// subclass from this base class by including the FILE as the first member of
+/// the subclass, and then likely adding more data members. The FILE
+/// structure contains pointers to the routines that implement I/O operations
+/// for derived classes. There is no requiremengt that a stream type implement
+/// every possible stream operation. If an unsupported operation is invoked
+/// on a stream then the call will simply return -ENXIO, unless otherwise
+/// specified.
+///
+/// The generic I/O calls use the same error-handling protocol as used by the
+/// SSX kernel services. A configuration setting (\c SSX_ERROR_CHECK_API)
+/// determines if error checks are made at all, and another setting (\c
+/// SSX_ERROR_PANIC) determines whether the presence of a fatal error causes a
+/// bad return code or an immediate panic.
+///
+/// The following errors are never considered fatal errors:
+///
+/// \b EOF Used to signal end-of-file
+///
+/// \b EAGAIN Used to signal that an operation was made to a non-blocking
+/// stream and the call would block.
+///
+/// Following are the specifications and requirements for the stream methods
+/// that implement a stream type.
+///
+/// <b> int sread(FILE *stream, void *buf, size_t count, size_t *read) </b>
+///
+/// The low-level read() function is named sread() here due to differences in
+/// the prototype and semantics from the Unix counterpart. The sread()
+/// functions attempts to read \a count bytes from the \a stream into \a buf,
+/// sets the number of bytes read, and returns either 0 for success or a
+/// negative error code. The only reason that sread() may terminate without
+/// reading \a count bytes is if sread() also returns a negative return
+/// code.
+///
+/// The device-specific sread() function may assume that the \a stream, \a buf
+/// and \a read parameters are non-NULL at entry, and the \a count is greater
+/// than 0. These conditions are checked/guaranteed by the generic interface.
+///
+/// <b> int swrite(FILE *stream, void *buf, size_t count, size_t *written) </b>
+///
+/// The low-level write() function is named swrite() here due to differences
+/// in the prototype and semantics from the Unix counterpart. The swrite()
+/// function attempts to writes \a count bytes from buf to the \a stream, sets
+/// the number of bytes written, and returns either 0 for success or a
+/// negative error code. The only reason that swrite() may terminate without
+/// writing \a count bytes is if write() also returns a negative return
+/// code.
+///
+/// The device-specific swrite() function may assume that the \a stream, \a
+/// buf and \a written parameters are non-NULL at entry, and the \a count is
+/// greater than 0. These conditions are checked/guaranteed by the generic
+/// interface.
+///
+/// <b> int fflush(FILE *stream) </b>
+///
+/// SSX implements the fflush() call, even though the semantics are slightly
+/// different from the Posix standard. The Posix fflush() returns either 0
+/// for success, or EOF to indicate an error. Here, fflush() returns negative
+/// 'errno' codes directly in the event of errors. The Posix standard
+/// specifies that calling fflush() with a NULL \a stream causes all open
+/// files to be flushed - here it returns the -EBADF error.
+///
+/// The stream-specific fflush() implementation should return one of the
+/// 'errno' codes specified by the Posix standard in the event of
+/// problems.
+
+#include "ssx.h"
+#include "ssx_io.h"
+
+/// Initialize an SSX I/O FILE structure
+///
+/// \param file A pointer to an uninitialized FILE
+///
+/// \param flags Flags for the generic FILE
+///
+/// This API is designed to be called from "constructors of classes derived
+/// from FILE", e.g., the StringStream. The generic FILE structure is
+/// cleared, and the flags are installed and other initialization based on the
+/// flags is performed. The subclass constructors then install function
+/// pointers for any of the FILE functions that they implement.
+///
+/// \retval 0 Success
+///
+/// \retval -FILE_INVALID_OBJECT The \a file pointer is null (0).
+///
+/// \retval -FILE_INVALID_ARGUMENT The \a flags are not valid.
+
+int
+FILE_create(FILE* file, int flags)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(file == 0, FILE_INVALID_OBJECT);
+ SSX_ERROR_IF(flags & ~SSX_FILE_VALID_FLAGS, FILE_INVALID_ARGUMENT);
+ SSX_ERROR_IF(__builtin_popcount(flags & SSX_FILE_OP_LOCK_OPTIONS) > 1,
+ FILE_INVALID_ARGUMENT);
+ }
+ memset((void*)file, 0, sizeof(FILE));
+ file->flags = flags;
+ ssx_semaphore_create(&(file->fop_sem), 1, 1);
+ return 0;
+}
+
+
+/// Assign an error code to a stream, returning a non-zero value for errors
+/// considered fatal.
+
+int
+ssx_io_error_set(FILE *stream, int code)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(stream == 0, EBADF);
+ }
+ stream->error = code;
+ if ((code == EOF) ||
+ (code == EAGAIN)) {
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+
+static int
+null_stream_sread(FILE *stream, void *buf, size_t count, size_t *read)
+{
+ *read = 0;
+ ssx_io_error_set(stream, EOF);
+ return EOF;
+}
+
+
+static int
+null_stream_swrite(FILE *stream, const void *buf, size_t count, size_t *written)
+{
+ *written = count;
+ return 0;
+}
+
+
+static int
+null_stream_fflush(FILE *stream)
+{
+ return 0;
+}
+
+
+/// A null stream; equivalent to Unix /dev/null
+///
+/// This stream is statically initialized as it is required to be assigned to
+/// \a ssxout at load time. The NULL stream does not require any locking.
+
+FILE _null_stream = {
+ .sread = null_stream_sread,
+ .swrite = null_stream_swrite,
+ .fflush = null_stream_fflush,
+ .error = 0,
+ .flags = 0
+};
+
+
+// It's up to the application to initialize the standard streams if it wishes
+// to use them. Reading or writing a NULL stream will signal an error.
+
+FILE *stdin = 0;
+FILE *stdout = 0;
+FILE *stderr = 0;
+
+/// Stream used by printk()
+///
+/// \a ssxout is the stream used by printk(). \a ssxout \e must be assigned
+/// to a non-blocking stream as it may be called from interrupt handlers. \a
+/// ssxout defaults to _null_stream, the equivalent of Unix' /dev/null.
+
+FILE *ssxout = &_null_stream;
+
+
+/// /dev/null for SSX
+FILE* ssxnull = &_null_stream;
+
+
+/// Lock low-level file operations
+///
+/// The decision on if and how low-level FILE operations needs to be locked is
+/// made by the class derived from FILE, and may also require an argument
+/// about its intended use. The minimum bar is always correctness. The next
+/// bar is whether the application allows data from multiple writers to be
+/// intermixed, or allows multiple readers to access the same input stream.
+///
+/// A device like the StringStream used to implement sprintf() and snprintf()
+/// does not require locking at all because it is only called from a single
+/// context. String streams that implement circular buffers must be locked if
+/// there is the possibility of multiple readers or writers, and the wrapping
+/// buffer always needs to be locked.
+///
+/// The lock implemented here is a lock on the low-level stream operations
+/// sread(), swrite() and fflush().
+
+#define LOCK_FILE_OPERATION(stream, operation) \
+ ({ \
+ int __rc; \
+ SsxMachineContext __ctx = SSX_THREAD_MACHINE_CONTEXT_DEFAULT; /* GCC */ \
+ if ((stream)->flags & SSX_FILE_OP_LOCK_OPTIONS) { \
+ if ((stream)->flags & SSX_FILE_OP_LOCK_CRITICAL) { \
+ ssx_critical_section_enter(SSX_CRITICAL, &__ctx); \
+ } else if ((stream)->flags & SSX_FILE_OP_LOCK_NONCRITICAL) { \
+ ssx_critical_section_enter(SSX_NONCRITICAL, &__ctx); \
+ } else { \
+ ssx_semaphore_pend(&((stream)->fop_sem), SSX_WAIT_FOREVER); \
+ } \
+ } \
+ __rc = (operation); \
+ if ((stream)->flags & SSX_FILE_OP_LOCK_OPTIONS) { \
+ if ((stream)->flags & (SSX_FILE_OP_LOCK_CRITICAL | \
+ SSX_FILE_OP_LOCK_NONCRITICAL)) { \
+ ssx_critical_section_exit(&__ctx); \
+ } else { \
+ ssx_semaphore_post(&((stream)->fop_sem)); \
+ } \
+ } \
+ __rc; \
+ })
+
+
+/// Call the sread() operation of a stream
+
+int
+sread(FILE *stream, void *buf, size_t count, size_t *read)
+{
+ ssize_t rc;
+ size_t _read;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF((stream == 0), EBADF);
+ SSX_IO_ERROR_IF(stream, (stream->sread == 0), ENXIO);
+ SSX_IO_ERROR_IF(stream, (buf == 0), EINVAL);
+ }
+ if (count == 0) {
+ if (read != 0) {
+ *read = 0;
+ }
+ return 0;
+ }
+ rc = LOCK_FILE_OPERATION(stream, stream->sread(stream, buf, count, &_read));
+ if (read != 0) {
+ *read = _read;
+ }
+ return rc;
+}
+
+
+/// Call the swrite() operation of a stream
+
+ssize_t
+swrite(FILE *stream, const void *buf, size_t count, size_t *written)
+{
+ ssize_t rc;
+ size_t _written;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF((stream == 0), EBADF);
+ SSX_IO_ERROR_IF(stream, (stream->swrite == 0), ENXIO);
+ SSX_IO_ERROR_IF(stream, (buf == 0), EINVAL);
+ }
+ if (count == 0) {
+ rc = 0;
+ _written = 0;
+ } else {
+ rc = LOCK_FILE_OPERATION(stream,
+ stream->swrite(stream, buf, count, &_written));
+ }
+ if (written != 0) {
+ *written = _written;
+ }
+ return rc;
+}
+
+
+/// Call the fflush() operation of the stream
+
+int
+fflush(FILE *stream)
+{
+ int rc;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_IO_ERROR_IF(stream, (stream == 0), EBADF);
+ SSX_IO_ERROR_IF(stream, (stream->fflush == 0), ENXIO);
+ }
+ rc = LOCK_FILE_OPERATION(stream, stream->fflush(stream));
+ return rc;
+}
diff --git a/src/lib/ppc405lib/ssx_io.h b/src/lib/ppc405lib/ssx_io.h
new file mode 100644
index 0000000..b30b32f
--- /dev/null
+++ b/src/lib/ppc405lib/ssx_io.h
@@ -0,0 +1,228 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/ssx_io.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __SSX_IO_H__
+#define __SSX_IO_H__
+
+// $Id: ssx_io.h,v 1.2 2014/02/03 01:30:25 daviddu Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/ssx_io.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ssx_io.h
+/// \brief SSX analog-replacement for C <stdio.h> and <unistd.h> functions
+
+#if !defined(_STDIO_H) && !defined(_UNISTD_H)
+
+#include "ssx_macros.h"
+#include "ssx_api.h"
+
+#include "ctype.h"
+#include "errno.h"
+#include "string.h"
+
+#define EOF -1
+
+#define FILE_INVALID_OBJECT 0x00345301
+#define FILE_INVALID_ARGUMENT 0x00345302
+
+#ifndef __ASSEMBLER__
+
+#include <stdarg.h>
+
+/// The SSX implementation of the FILE structure
+
+typedef struct FILE {
+
+ /// The sread() method
+ int (*sread)(struct FILE *stream, void *buf,
+ size_t count, size_t *read);
+
+ /// The swrite() method
+ int (*swrite)(struct FILE *stream, const void *buf,
+ size_t count, size_t *written);
+
+ /// The fflush() method
+ int (*fflush)(struct FILE *stream);
+
+ /// The last error code encountered
+ ///
+ /// This field is not set in the event of an error panic.
+ int error;
+
+ /// SSX file/stream flags; See \ref ssx_file_flags
+ int flags;
+
+ /// The semaphore used to lock low-level file operations if required.
+ SsxSemaphore fop_sem;
+
+ /// The number of newline characters read by fgetc.
+ ///
+ /// This variable supports an SSX extension to <stdio.h>, the flines()
+ /// API. flines() returns the number of newline characters read by
+ /// fgetc(). This counter does not count newline characters read using
+ /// sread() on the stream directly.
+ size_t lines;
+
+ /// The character pushed back by ungetc()
+ ///
+ /// If a character is back the flag SSX_FILE_HAS_CHARACTER will be
+ /// set. Note that characters pushed back with ungetc() are not returned
+ /// by any subsequent sread() call on the stream, so it is best not to mix
+ /// sread() and fgetc().
+ unsigned char character;
+
+} FILE;
+
+
+/// \defgroup ssx_file_flags SSX File/Stream Flags
+/// @{
+
+/// Low-level access is locked by an SSX_CRITICAL critical section
+#define SSX_FILE_OP_LOCK_CRITICAL 0x1
+
+/// Low-level access is locked by an SSX_NONCRITICAL critical section
+#define SSX_FILE_OP_LOCK_NONCRITICAL 0x2
+
+/// Low-level access is locked by a semaphore
+#define SSX_FILE_OP_LOCK_SEMAPHORE 0x4
+
+/// Mask of all locking options;
+#define SSX_FILE_OP_LOCK_OPTIONS 0x7
+
+/// The FILE has a character pushed back by ungetc()
+#define SSX_FILE_HAS_CHARACTER 0xf
+
+/// All valid flags
+#define SSX_FILE_VALID_FLAGS 0xf
+
+/// @}
+
+
+extern FILE *stdin;
+extern FILE *stdout;
+extern FILE *stderr;
+
+/// SSX kernel output stream
+///
+/// This stream implements the printk() API. It must be a non-blocking stream
+/// so that it can be used in interrupt contexts.
+
+extern FILE *ssxout;
+
+extern FILE *ssxnull;
+
+int
+FILE_create(FILE *stream, int flags);
+
+int
+sread(FILE *stream, void *buf, size_t count, size_t *read);
+
+int
+swrite(FILE *stream, const void *buf, size_t count, size_t *written);
+
+int
+fflush(FILE *stream);
+
+int
+vfprintf(FILE *stream, const char *format, va_list argp)
+ __attribute__ ((format (printf, 2, 0)));
+
+int
+vprintf(const char *format, va_list argp)
+ __attribute__ ((format (printf, 1, 0)));
+
+int
+fprintf(FILE *stream, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+
+int
+printf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+
+int
+printk(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+
+int
+vsprintf(char *str, const char *format, va_list argp)
+ __attribute__ ((format (printf, 2, 0)));
+
+int
+sprintf(char *str, const char *format, ...)
+ __attribute__ ((format (printf, 2, 3)));
+
+int
+vsnprintf(char *str, size_t size, const char *format, va_list argp)
+ __attribute__ ((format (printf, 3, 0)));
+
+int
+snprintf(char *str, size_t size, const char *format, ...)
+ __attribute__ ((format (printf, 3, 4)));
+
+int
+fputc(int c, FILE *stream);
+
+int
+fputs(const char *s, FILE *stream);
+
+int
+puts(const char *s);
+
+int
+putchar(int c);
+
+int
+fgetc(FILE* stream);
+
+int
+ungetc(int c, FILE* stream);
+
+size_t
+flines(FILE* stream);
+
+int
+ssx_io_error_set(FILE *stream, int code);
+
+/// Handle I/O errors including panic configurations
+#define SSX_IO_ERROR_IF(stream, condition, code) \
+ do { \
+ if (condition) { \
+ if (ssx_io_error_set(stream, code) && SSX_ERROR_PANIC) { \
+ SSX_PANIC(code); \
+ } else { \
+ return -(code); \
+ } \
+ } \
+ } while (0)
+
+#define SSX_IO_ERROR(stream, code) SSX_IO_ERROR_IF((stream), 1, (code))
+
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* !defined(_STDIO_H) && !defined(_UNISTD_H) */
+
+#endif /* __SSX_IO_H__ */
diff --git a/src/lib/ppc405lib/stdlib.c b/src/lib/ppc405lib/stdlib.c
new file mode 100644
index 0000000..a15308d
--- /dev/null
+++ b/src/lib/ppc405lib/stdlib.c
@@ -0,0 +1,115 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/stdlib.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: stdlib.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/stdlib.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file stdlib.c
+/// \brief Functions from <stdlib.h>
+///
+/// \note The strtoX() APIs are defined in strtox.[ch]
+
+#include "ssx.h"
+#include "ctype.h"
+#include "libssx.h"
+#include <stdlib.h>
+
+
+/// Convert a string to a long integer - base 10 only
+///
+/// atol(str) is defined here as strtol(str, 0, 10) in sympathy with the POSIX
+/// standard. Note that by specification "atol() does not detect
+/// errors", however here it will behave the same as the strtol() call just
+/// mentioned.
+
+long
+atol(const char *str)
+{
+ return strtol(str, 0, 10);
+}
+
+
+/// Convert a string to an integer - base 10 only
+///
+/// atoi(str) is defined here as strtol(str, 0, 10) in sympathy with the POSIX
+/// standard. Note that by specification "atoi() does not detect errors",
+/// however in this implementation the long integer returned by the strtol()
+/// call just mentioned is simply converted to an int.
+
+int
+atoi(const char *str)
+{
+ return strtol(str, 0, 10);
+}
+
+
+/// 'Exit' an application
+///
+/// An SSX application can not really 'exit'. By convention, exit(0) is the
+/// same as ssx_halt(). Calling exit() with a non-zero code causes a kernel
+/// panic - the exit code will be found in R3 on PowerPC.
+///
+/// Note that to exit a thread, the thread can either return from the thread
+/// entry routine or explicitly call ssx_complete(). exit() was implemented
+/// to allow porting of the EEMBC benchmarks.
+
+void
+exit(int status)
+{
+ if (status) {
+ SSX_PANIC(ERROR_EXIT);
+ }
+ ssx_halt();
+}
+
+
+/// Compute the absolute value of the integer argument
+int
+abs(int i)
+{
+ return ((i < 0) ? -i : i);
+}
+
+
+/// Compute the absolute value of the long integer argument
+long int
+labs(long int i)
+{
+ return ((i < 0) ? -i : i);
+}
+
+
+/// Compute the absolute value of the long long integer argument
+long long int
+llabs(long long int i)
+{
+ return ((i < 0) ? -i : i);
+}
+
+
diff --git a/src/lib/ppc405lib/strcasecmp.c b/src/lib/ppc405lib/strcasecmp.c
new file mode 100644
index 0000000..fc7585c
--- /dev/null
+++ b/src/lib/ppc405lib/strcasecmp.c
@@ -0,0 +1,90 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/strcasecmp.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: strcasecmp.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/strcasecmp.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file strcasecmp.c
+/// \brief Implementation of strcasecmp() and strncasecmp()
+///
+/// These routines are rarely used, hence broken out into a separate file to
+/// save code space for most applications.
+
+#include "ssx.h"
+#include "string.h"
+
+/// Compare two strings ignoring case
+///
+/// The strcasecmp() function compares the two strings \a s1 and \a s2,
+/// ignoring the case of the characters. It returns an integer less than,
+/// equal to, or greater than zero if \a s1 is found, respectively, to be less
+/// than, to match, or be greater than \a s2.
+
+int
+strcasecmp(const char* s1, const char* s2)
+{
+ int rc;
+
+ if (s1 == s2) {
+ rc = 0;
+ } else {
+ while(*s1 && (tolower(*s1) == tolower(*s2))) {
+ s1++;
+ s2++;
+ }
+ rc = *((unsigned char *)s1) - *((unsigned char *)s2);
+ }
+ return rc;
+}
+
+
+/// Compare a portion of two strings ignoring case
+///
+/// The strncmp() function compares at most the first \n characters of the two
+/// strings \a s1 and \a s2, ignoring the case of the characters. It returns
+/// an integer less than, equal to, or greater than zero if (the prefix of) \a
+/// s1 is found, respectively, to be less than, to match, or be greater than
+/// (the prefix of) \a s2.
+
+int
+strncasecmp(const char* s1, const char* s2, size_t n)
+{
+ int rc;
+
+ if ((s1 == s2) || (n == 0)) {
+ rc = 0;
+ } else {
+ while(*s1 && (tolower(*s1) == tolower(*s2)) && n--) {
+ s1++;
+ s2++;
+ }
+ rc = *((unsigned char *)s1) - *((unsigned char *)s2);
+ }
+ return rc;
+}
diff --git a/src/lib/ppc405lib/strdup.c b/src/lib/ppc405lib/strdup.c
new file mode 100644
index 0000000..6d205c7
--- /dev/null
+++ b/src/lib/ppc405lib/strdup.c
@@ -0,0 +1,63 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/strdup.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: strdup.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/strdup.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file strdup.c
+/// \brief Functions from <string.h> that require malloc()
+///
+/// These APIs are split from string.c for the benefit of applications like
+/// OCC FW that don't use malloc().
+
+#include <stdlib.h>
+#include <string.h>
+
+/// Duplicate a string
+///
+/// \param s The string to duplicate
+///
+/// The strdup() function returns a pointer to a new string which is a
+/// duplicate of the input string \a s. Memory for the new string is obtained
+/// with malloc(), and can be freed with free().
+///
+/// \returns The strdup() function returns a pointer to the duplicated string,
+/// or NULL (0) if insufficient memory was available.
+
+char *
+strdup(const char* s)
+{
+ char* dup;
+
+ dup = (char*)malloc(strlen(s) + 1);
+ if (dup != 0) {
+ strcpy(dup, s);
+ }
+ return dup;
+}
diff --git a/src/lib/ppc405lib/string_stream.c b/src/lib/ppc405lib/string_stream.c
new file mode 100644
index 0000000..1dfc439
--- /dev/null
+++ b/src/lib/ppc405lib/string_stream.c
@@ -0,0 +1,410 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/string_stream.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: string_stream.c,v 1.2 2014/02/03 01:30:25 daviddu Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/string_stream.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file string_stream.c
+/// \brief Implementations of string streams.
+///
+/// \bug Need to work out overwrite/multiple-write protection.
+
+#include "ssx.h"
+#include "string_stream.h"
+
+
+// 'Flush' a string stream by making it empty
+
+static int
+string_stream_fflush(FILE* stream)
+{
+ StringStream* string = (StringStream*) stream;
+
+ string->next_read = 0;
+ string->next_write = 0;
+ string->flags &= ~STRING_STREAM_FULL;
+ return 0;
+}
+
+
+// Read the remaining tail (if any) of the circular buffer, assuming the
+// buffer is not empty.
+
+static size_t
+read_tail(StringStream* string, void* buf, size_t size)
+{
+ size_t read, remainder;
+
+ read = 0;
+ if (string->next_read >= string->next_write) {
+
+ remainder = string->size - string->next_read;
+ read = MIN(size, remainder);
+ memcpy(buf, (void *)(&(string->data[string->next_read])), read);
+ if (read != remainder) {
+ string->next_read += read;
+ } else {
+ string->next_read = 0;
+ }
+ }
+ return read;
+}
+
+
+// Read the area (if any) from the read pointer to the write pointer
+
+static size_t
+read_head(StringStream* string, void* buf, size_t size)
+{
+ size_t read, remainder;
+
+ read = 0;
+ if (string->next_write > string->next_read) {
+
+ remainder = string->next_write - string->next_read;
+ read = MIN(size, remainder);
+ memcpy(buf, (void *)(&(string->data[string->next_read])), read);
+ string->next_read += read;
+ }
+ return read;
+}
+
+
+// Read as much data as possible from a circular buffer. Return -EAGAIN if the
+// buffer would underflow.
+
+static int
+string_stream_sread(FILE* stream, void* buf, size_t size, size_t* read)
+{
+ StringStream *string = (StringStream *)stream;
+ size_t were_read;
+ int rc;
+
+ if ((string->next_read == string->next_write) &&
+ !(string->flags & STRING_STREAM_FULL)) {
+ were_read = 0;
+ } else {
+ were_read = read_tail(string, buf, size);
+ if (were_read != size) {
+ were_read += read_head(string, buf + were_read, size - were_read);
+ }
+ }
+ if (were_read != 0) {
+ string->flags &= ~STRING_STREAM_FULL;
+ }
+ *read = were_read;
+ if (were_read < size) {
+ rc = -EAGAIN;
+ } else {
+ rc = 0;
+ }
+ return rc;
+}
+
+
+
+
+// Write the remaining tail (if any) of the circular buffer, assuming the
+// buffer is not full.
+
+static size_t
+write_tail(StringStream* string, const void* buf, size_t size)
+{
+ size_t written, remainder;
+
+ written = 0;
+ if (string->next_write >= string->next_read) {
+
+ remainder = string->size - string->next_write; // string->size is the size of the stream(our buffer)
+ written = MIN(size, remainder);
+ // memcpy(void *dest, const void *src, size_t n) from /lib/memcpy.c
+ memcpy((void *)(&(string->data[string->next_write])), buf, written);
+ if (written != remainder) {
+ string->next_write += written;
+ } else {
+ string->next_write = 0;
+ }
+ }
+ return written;
+}
+
+// Write the area (if any) from the write pointer to the read pointer
+
+static size_t
+write_head(StringStream* string, const void* buf, size_t size)
+{
+ size_t written, remainder;
+
+ written = 0;
+ if (string->next_read > string->next_write) {
+
+ remainder = string->next_read - string->next_write;
+ written = MIN(size, remainder);
+ memcpy((void *)(&(string->data[string->next_write])), buf, written);
+ string->next_write += written;
+ }
+ return written;
+}
+
+
+// Write as much data as possible to a circular buffer. Return -EAGAIN if the
+// buffer would overflow.
+
+static int
+circular_swrite(FILE* stream, const void* buf, size_t size, size_t* written)
+{
+ StringStream *string = (StringStream *)stream;
+ size_t wrote;
+ int rc;
+
+ if (string->flags & STRING_STREAM_FULL) {
+ wrote = 0;
+ } else {
+ wrote = write_tail(string, buf, size);
+ if (wrote != size) {
+ wrote += write_head(string, buf + wrote, size - wrote);
+ }
+ }
+ if ((wrote != 0) && (string->next_read == string->next_write)) {
+ string->flags |= STRING_STREAM_FULL;
+ }
+ *written = wrote;
+ if (wrote < size) {
+ rc = -EAGAIN;
+ } else {
+ rc = 0;
+ }
+ return rc;
+}
+
+
+// Effectively write all data to a circular buffer with wrapping semantics.
+
+static int
+wrapping_swrite(FILE* stream, const void* buf, size_t size, size_t* written)
+{
+ StringStream *string = (StringStream *)stream;
+ size_t wrote;
+ int rc;
+
+ if (size >= string->size) { // If size of data >= size of buffer
+
+ // If the amount of data will fill or overflow the entire buffer size
+ // then we effectively fill the buffer with the final bytes of data.
+
+ string->next_read = 0;
+ string->next_write = 0;
+ string->flags |= STRING_STREAM_FULL;
+ memcpy((void *)string->data, buf + (size - string->size), size);
+
+ } else {
+
+ // If the string is not full, try to fill it with the
+ // circular_swrite().
+
+ if (string->flags & STRING_STREAM_FULL) {
+ wrote = 0;
+ rc = -EAGAIN;
+ } else {
+ rc = circular_swrite(stream, buf, size, &wrote);
+ }
+ if (rc) {
+
+ // The string is full and we need to overflow. We know that size
+ // is less than the buffer size, and the next_read == next_write.
+ // Mark the stream not full so a new circular write will work, and
+ // at the end reset the full condition.
+
+ string->flags &= ~STRING_STREAM_FULL;
+ rc = circular_swrite(stream, buf + wrote, size - wrote, &wrote);
+ if (rc) {
+ SSX_PANIC(STRING_STREAM_BUG);
+ }
+ string->next_read = string->next_write;
+ string->flags |= STRING_STREAM_FULL;
+ }
+ }
+ *written = size;
+ return 0;
+}
+
+
+static int
+linear_swrite(FILE* stream, const void* buf, size_t size, size_t* written)
+{
+ // buf and size correspond to the data we are passing to our own buffer
+ uint32_t bit_0_mask = 0x80000000;
+ StringStream *string = (StringStream *)stream;
+ size_t wrote = 0; // right aligned
+ // int rc;
+ uint32_t num_bytes_written;
+ // uint32_t register_contents;
+
+
+ //if (wrote != size) {
+ // register_contents = in32(PMC_PORE_SCRATCH_REG1);
+ // register_contents = register_contents & bit_0_mask;
+
+ //if (!register_contents) {
+ // Before writing to SRAM, flush everything so it will write to the top
+ // of the buffer each time
+ string_stream_fflush(stream);
+
+ // Write printk statement to SRAM
+ // wrote will contain the number of bytes written
+
+ wrote += write_tail(string, buf + wrote, size - wrote);
+ // if wrote != size, tell Tcl to read the whole buffer, When Tcl is done loop back to write_tail
+ // buf= buf+wrote
+ // size= size - wrote
+ // continue loop until size = 0
+
+ // Sync
+ eieio();
+
+ // Store "wrote" to register
+ // Set bit 0 to 1
+ // out32(addr, data)
+ num_bytes_written = (uint32_t)wrote | bit_0_mask;
+ out32( PMC_PORE_SCRATCH_REG1 , num_bytes_written );
+
+ // Sync
+ eieio();
+ //}
+ //}
+
+ // outside of loop, set *written = wrote (which is equal to size once all data has been copied to our buffer)
+ *written = wrote;
+ return 0;
+
+}
+
+
+int
+_string_stream_create(StringStream* stream,
+ void* buf, size_t size, int flags,
+ int (*swrite)(FILE* stream,
+ const void* buf,
+ size_t size,
+ size_t* written))
+{
+ FILE* file = (FILE*)stream;
+ int rc;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF((stream == 0) ||
+ ((buf == 0) && (size != 0)),
+ STRING_STREAM_INVALID_ARGUMENT);
+ }
+
+ rc = FILE_create(file, flags);
+
+ if (!rc) {
+ file->swrite = swrite;
+ file->sread = string_stream_sread;
+ file->fflush = string_stream_fflush;
+ stream->data = buf;
+ stream->size = size;
+ stream->next_read = 0;
+ stream->next_write = 0;
+ stream->flags = 0;
+ }
+ return rc;
+}
+
+
+int
+circular_stream_create(CircularStream* stream,
+ void* buf, size_t size, int flags)
+{
+ return _string_stream_create(stream, buf, size, flags, circular_swrite);
+}
+
+
+int
+wrapping_stream_create(CircularStream* stream,
+ void* buf, size_t size, int flags)
+{
+ return _string_stream_create(stream, buf, size, flags, wrapping_swrite);
+}
+
+
+int
+linear_stream_create(CircularStream* stream,
+ void* buf, size_t size, int flags)
+{
+ FILE* file = (FILE*)stream;
+ int rc;
+
+ rc = _string_stream_create(stream, buf, size, flags, linear_swrite);
+ if (!rc) {
+
+ file->sread = NULL;
+ // Write to register where location of buffer is
+ out32( PMC_PORE_SCRATCH_REG1, (uint32_t)buf);
+ }
+ return rc;
+}
+
+
+// InputStream uses string_stream_sread(), however returns EOF once all data
+// has been read.
+
+static int
+input_stream_sread(FILE* stream, void* buf, size_t size, size_t* read)
+{
+ int rc;
+
+ rc = string_stream_sread(stream, buf, size, read);
+ if (rc == -EAGAIN) {
+ rc = EOF;
+ }
+
+ return rc;
+}
+
+
+// For simplicity (and ease of maintainence) we create a normal string stream
+// then overwrite a few key fields.
+
+int
+input_stream_create(StringStream* stream, void* buf, size_t size, int flags)
+{
+ int rc;
+
+ rc = _string_stream_create(stream, buf, size, flags, 0);
+ if (!rc) {
+ stream->stream.sread = input_stream_sread;
+ stream->stream.fflush = 0;
+ stream->flags = STRING_STREAM_FULL;
+ }
+ return rc;
+}
+
+
diff --git a/src/lib/ppc405lib/string_stream.h b/src/lib/ppc405lib/string_stream.h
new file mode 100644
index 0000000..07891f5
--- /dev/null
+++ b/src/lib/ppc405lib/string_stream.h
@@ -0,0 +1,277 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/string_stream.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __STRING_STREAM_H__
+#define __STRING_STREAM_H__
+
+// $Id: string_stream.h,v 1.2 2014/02/03 01:30:25 daviddu Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/string_stream.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file string_stream.h
+/// \brief Implementations of string streams.
+
+#include "ssx_io.h"
+
+/// A string stream
+///
+/// This structure is used for the public CircularStream and WrappingStream
+/// types, as well as for the library-internal types used to implement
+/// sprintf() and snprintf().
+
+typedef struct {
+
+ /// The base class
+ FILE stream;
+
+ /// Data storage - provided by the creator
+ uint8_t *data;
+
+ /// The size of the data storage
+ size_t size;
+
+ /// The index of the next byte to write
+ size_t next_write;
+
+ /// The index of the next byte to read
+ size_t next_read;
+
+ /// Stream flags, see \ref string_stream_flags
+ int flags;
+
+} StringStream;
+
+
+/// A StringStream with circular buffer semantics
+///
+/// The swrite() method copies the input data to the stream buffer, which is
+/// treated as a circular buffer. If the swrite() would overflow the buffer,
+/// then as much data as possible is written and swrite returns -EAGAIN. In
+/// all cases swrite() returns the number of bytes actually written to the
+/// buffer.
+///
+/// The sread() method copies data from the StringStream circular buffer to
+/// the caller's buffer until either the caller's request is satisfied or all
+/// of the immediately available data has been read from the buffer. If the
+/// caller's request can not be immediately granted then as much data as
+/// possible is copied and sread() returns -EAGAIN. In all cases sread()
+/// returns the number of bytes actually read from the buffer.
+///
+/// The fflush() method marks the buffer as empty, effectively losing any data
+/// currently stored in the buffer.
+
+typedef StringStream CircularStream;
+
+
+/// A StringStream with wrapping circular buffer semantics
+///
+/// The swrite() method copies the input data to the stream buffer, which is
+/// treated as a circular buffer. If the swrite() would overflow the buffer,
+/// then unread data is overwritten with new data. If the size of the
+/// swrite() exceeds the buffer length then the effect is simply to fill the
+/// buffer with the final bytes of the caller's data. swrite() always returns
+/// the number of bytes requested to be written.
+///
+/// The sread() method copies data from the StringStream circular buffer to
+/// the caller's buffer until either the caller's request is satisfied or all
+/// of the immediately available data has been read from the buffer. If the
+/// caller's request can not be immediately granted then as much data as
+/// possible is copied and sread() returns -EAGAIN. In all cases sread()
+/// returns the number of bytes actually read from the buffer.
+///
+/// The fflush() method marks the buffer as empty, effectively losing any data
+/// currently stored in the buffer.
+
+typedef StringStream WrappingStream;
+
+
+/// Create a StringStream
+///
+/// \param stream The StringStream to initialize
+///
+/// \param buf The stream data buffer
+///
+/// \param size The size of the data buffer in bytes
+///
+/// \param flags Flags for FILE_create()
+///
+/// \param swrite The function to be installed as the swrite() function for
+/// the underlying FILE object. The sread() and fflush() functions are fixed.
+///
+/// This API initializes a StringStream structure for use in I/O operations.
+/// This API will typically only be used by the creation functions of specific
+/// StringStream types.
+///
+/// \retval 0 Success
+///
+/// \retval -STRING_STREAM_INVALID_ARGUMENT Either \a stream is NULL (0)
+/// or \a buf is NULL(0) and \a size is non-0.
+
+int
+_string_stream_create(StringStream* stream,
+ void* buf, size_t size, int flags,
+ int (*swrite)(FILE* stream,
+ const void* buf,
+ size_t size,
+ size_t* written));
+
+/// Create a CircularStream
+///
+/// \param stream The CircularStream to initialize
+///
+/// \param buf The stream data buffer
+///
+/// \param size The size of the data buffer in bytes
+///
+/// \param flags Flags for FILE_create()
+///
+/// This API initializes a CircularStream structure for use in I/O
+/// operations. Once created, the pointer to the CircularStream stream can be
+/// cast to a FILE* and used for sread(), swrite(), fflush() and fprintf()
+/// operations.
+///
+/// \retval 0 Success
+///
+/// \retval -STRING_STREAM_INVALID_ARGUMENT Either \a stream is NULL (0)
+/// or \a buf is NULL(0) and \a size is non-0.
+
+int
+circular_stream_create(CircularStream* stream,
+ void* buf, size_t size, int flags);
+
+
+/// Create a WrappingStream
+///
+/// \param stream The WrappingStream to initialize
+///
+/// \param buf The stream data buffer
+///
+/// \param size The size of the data buffer in bytes
+///
+/// \param flags Flags for FILE_create()
+///
+/// This API initializes a WrappingStream structure for use in I/O
+/// operations. Once created, the pointer to the WrappingStream stream can be
+/// cast to a FILE* and used for sread(), swrite(), fflush() and fprintf()
+/// operations.
+///
+/// \retval 0 Success
+///
+/// \retval -STRING_STREAM_INVALID_ARGUMENT Either \a stream is NULL (0)
+/// or \a buf is NULL(0) and \a size is non-0.
+
+int
+wrapping_stream_create(CircularStream* stream,
+ void* buf, size_t size, int flags);
+
+
+/// Create a LinearStream
+///
+/// \param stream The LinearStream to initialize
+///
+/// \param buf The stream data buffer
+///
+/// \param size The size of the data buffer in bytes
+///
+/// \param flags Flags for FILE_create()
+///
+/// This API initializes a LinearStream structure for use in I/O
+/// operations. Once created, the pointer to the WrappingStream stream can be
+/// cast to a FILE* and used for sread(), swrite(), fflush() and fprintf()
+/// operations.
+///
+/// \retval 0 Success
+///
+/// \retval -STRING_STREAM_INVALID_ARGUMENT Either \a stream is NULL (0)
+/// or \a buf is NULL(0) and \a size is non-0.
+
+
+int
+linear_stream_create(CircularStream* stream,
+ void* buf, size_t size, int flags);
+
+
+/// A StringStream used as a read-only input stream
+///
+/// This is a CircualarStream created with a full buffer and without a write
+/// method. It uses a special read method that returns EOF once the buffer is
+/// empty rather than -EAGAIN.
+
+typedef StringStream InputStream;
+
+
+/// Create an InputStream
+///
+/// \param stream The InputStream to initialize
+///
+/// \param buf The stream data buffer.
+///
+/// \param size The size of the readable portion of the data buffer in bytes
+///
+/// \param flags Flags for FILE_create()
+///
+/// This API initializes an InputStream structure for use in input operations.
+/// The stream data buffer contains \a size bytes of data which can be read.
+/// Once created, the pointer to the InputStream stream can be cast to a FILE*
+/// and used for sread(), fgetc() and ungetc() operations. Neither fflush()
+/// nor swrite() are supported on this class of stream. The read operations
+/// will succeed until \a size bytes have been returned from the stream, at
+/// which point the stream will return EOF on any subsequent reads.
+///
+/// \retval 0 Success
+///
+/// \retval -STRING_STREAM_INVALID_ARGUMENT Either \a stream is NULL (0)
+/// or \a buf is NULL(0) and \a size is non-0.
+
+int
+input_stream_create(InputStream* stream,
+ void* buf, size_t size, int flags);
+
+
+/// \defgroup string_stream_flags StringStream Flags
+///
+/// @{
+
+/// The StringStream is full
+#define STRING_STREAM_FULL 0x1
+
+/// @}
+
+
+/// \defgroup string_stream_codes StringStream Error/Panic Codes
+///
+/// @{
+
+/// A bug was detected in a StringStream function
+#define STRING_STREAM_BUG 0x00787701
+#define STRING_STREAM_INVALID_ARGUMENT 0x00787702
+
+/// @}
+
+
+#endif // __STRING_STREAM_H__
diff --git a/src/lib/ppc405lib/strtox.c b/src/lib/ppc405lib/strtox.c
new file mode 100644
index 0000000..56493fa
--- /dev/null
+++ b/src/lib/ppc405lib/strtox.c
@@ -0,0 +1,617 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/strtox.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: strtox.c,v 1.2 2014/02/03 01:30:25 daviddu Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/strtox.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file strtox.c
+/// \brief Implementation of strtol(), strtoul(), strtoll() and strtoull()
+///
+/// <b> Standard String Conversion Routines </b>
+///
+/// This file contains implementaions of strtol(), strtoul(), strtoll() and
+/// strtoull(). These APIs are all called as
+///
+/// \code
+/// strtoX(const char* str, char** endptr, int base)
+/// \endcode
+///
+/// where X is
+///
+/// - l : Convert to a long integer
+/// - ul : Convert to an unsigned long integer
+/// - ll : Convert to a long long integer
+/// - ull : Convert to an unsigned long long integer
+///
+/// \param str The string to convert
+///
+/// \param endptr If non-null, will be set to a pointer to the portion of the
+/// string following the convertable portion. If no conversion is performed
+/// then the original \a str is returned here.
+///
+/// \param base Either 0 to indicate that the base should be derived from
+/// radix markers in the string, or a number in the range 2 to 36 inclusive.
+///
+/// The APIs convert the initial portion of the string pointed to by \a str to
+/// an integer, which is either a long integer (strtol), an unsigned long
+/// (strtoul()), a long long (strtoll), or an unsigned long long
+/// (strtoull). First, the APIs decompose the input string into three parts:
+///
+/// - An initial, possibly empty, sequence of white-space characters (as
+/// specified by isspace())
+///
+/// - A subject sequence interpreted as an integer represented in some radix
+/// determined by the value of \a base
+///
+/// - A final string of one or more unrecognized characters, including the
+/// terminating null byte of the input string.
+///
+/// The APIs then attempt to convert the subject sequence to an integer of the
+/// required type and returns the result.
+///
+/// If the value of \a base is 0, the expected form of the subject sequence is
+/// that of a decimal constant, octal constant, or hexadecimal constant, any
+/// of which may be preceded by a '+' or '-' sign. A decimal constant begins
+/// with a non-zero digit, and consists of a sequence of decimal digits. An
+/// octal constant consists of the prefix '0' optionally followed by a
+/// sequence of the digits '0' to '7' only. A hexadecimal constant consists of
+/// the prefix 0x or 0X followed by a sequence of the decimal digits and
+/// letters 'a' (or 'A' ) to 'f' (or 'F' ) with values 10 to 15 respectively.
+///
+/// If the value of \a base is between 2 and 36, the expected form of the
+/// subject sequence is a sequence of letters and digits representing an
+/// integer with the radix specified by base, optionally preceded by a '+' or
+/// '-' sign. The letters from 'a' (or 'A' ) to 'z' (or 'Z' ) inclusive are
+/// ascribed the values 10 to 35; only letters whose ascribed values are less
+/// than that of base are permitted. If the value of base is 16, the
+/// characters 0x or 0X may optionally precede the sequence of letters and
+/// digits, following the sign if present.
+///
+/// The subject sequence is defined as the longest initial subsequence of the
+/// input string, starting with the first non-white-space character that is of
+/// the expected form. The subject sequence contains no characters if the
+/// input string is empty or consists entirely of white-space characters, or if
+/// the first non-white-space character is other than a sign or a permissible
+/// letter or digit.
+///
+/// If the subject sequence has the expected form and the value of base is 0,
+/// the sequence of characters starting with the first digit will be
+/// interpreted as an integer constant. If the subject sequence has the
+/// expected form and the value of base is between 2 and 36, it will be used
+/// as the base for conversion, ascribing to each letter its value as given
+/// above. If the subject sequence begins with a minus sign, the value
+/// resulting from the conversion will be negated. A pointer to the final
+/// string will be stored in the object pointed to by \a endptr, provided that
+/// \a endptr is not a null pointer.
+///
+/// If the subject sequence is empty or does not have the expected form, no
+/// conversion is performed; the value of \a str is stored in the object
+/// pointed to by \a endptr, provided that \a endptr is not a null pointer.
+///
+/// Note that the unsigned APIs silently convert signed representations into
+/// the equivalent unsigned number.
+///
+/// Since 0, (L)LONG_MIN and (U)(L)LONG_MAX are returned on error and are
+/// also valid returns on success, there is no way for an SSX application to
+/// determine whether the conversion succeeded or failed (since SSX does not
+/// support \a errno). For this reason it is recommended that SSX-only
+/// applications use the underlying APIs _strtol(), _strtoul(), _strtoll() and
+/// _strtoull(), or even better the extended APIs strtoi32(), strtou32(),
+/// strtoi64() or strtou64() discussed further below.
+///
+/// Upon successful completion, strtoX() returns the converted
+/// value, if any. If no conversion could be performed or there was an error
+/// in the base specification, 0 is returned.
+///
+/// If the correct value is outside the range of representable values,
+/// (L)LONG_MIN or (U)(L)LONG_MAX will be returned (according to the sign
+/// and type of the value).
+///
+/// Note: This specification is adapted from IEEE Std. 10003.1, 2003 Edition
+///
+///
+/// <b> Underlying APIs </b>
+///
+/// The APIs underlying the standard APIs are all called as
+///
+/// \code
+/// int _strtoX(const char* str, char** endptr, int radix, <type>* value)
+/// \endcode
+///
+/// where X is
+///
+/// - l : Convert to a long integer
+/// - ul : Convert to an unsigned long integer
+/// - ll : Convert to a long long integer
+/// - ull : Convert to an unsigned long long integer
+///
+/// \param str The string to convert
+///
+/// \param endptr If non-null, will be set to a pointer to the portion of the
+/// string following the convertable portion. If no conversion is performed
+/// then the original \a str is returned here.
+///
+/// \param base Either 0 to indicate that the base should be derived from
+/// radix markers in the string, or a number in the range 2 to 36 inclusive.
+///
+/// \param value The converted value, returned as the return value of the
+/// standard API.
+///
+/// The return value of the underlying APIs is one of the following
+///
+/// \retval 0 Success
+///
+/// \retval -STRTOX_NO_CONVERSION_EMPTY No conversion was performed because the
+/// string was effectively empty.
+///
+/// \retval -STRTOX_NO_CONVERSION_PARSE No conversion was performed because the
+/// string did not parse as an integer.
+///
+/// \retval -STRTOX_INVALID_ARGUMENT No conversion was performed because the
+/// \a base specification was not valid.
+///
+/// \retval -STRTOX_UNDERFLOW_STRTOL1 Conversion resulted in underflow
+///
+/// \retval -STRTOX_UNDERFLOW_STRTOL2 Conversion resulted in underflow
+///
+/// \retval -STRTOX_UNDERFLOW_STRTOLL1 Conversion resulted in underflow
+///
+/// \retval -STRTOX_UNDERFLOW_STRTOLL2 Conversion resulted in underflow
+///
+/// \retval -STRTOX_OVERFLOW_STRTOL1 Conversion resulted in overflow
+///
+/// \retval -STRTOX_OVERFLOW_STRTOL2 Conversion resulted in overflow
+///
+/// \retval -STRTOX_OVERFLOW_STRTOLL1 Conversion resulted in overflow
+///
+/// \retval -STRTOX_OVERFLOW_STRTOLL2 Conversion resulted in overflow
+///
+///
+/// <b> Extended APIs </b>
+///
+/// The extended APIs are the preferred way to do portable integer
+/// conversion. These APIs are all called as
+///
+/// \code
+/// int strtoX(const char* str, char** endptr, int radix, <type>* value)
+/// \endcode
+///
+/// where X is
+///
+/// - i32 : Convert to an int32_t
+/// - u32 : Convert to a uint32_t
+/// - i64 : Convert to an int64_t
+/// - u64 : Convert to a uint64_t
+///
+/// \param str The string to convert
+///
+/// \param endptr If non-null, will be set to a pointer to the portion of the
+/// string following the convertable portion. If no conversion is performed
+/// then the original \a str is returned here.
+///
+/// \param base Either 0 to indicate that the base should be derived from
+/// radix markers in the string, or a number in the range 2 to 36 inclusive.
+///
+/// \param value The converted value
+///
+/// The return value of the underlying APIs is one of the following
+///
+/// \retval 0 Success
+///
+/// \retval -STRTOX_NO_CONVERSION_EMPTY No conversion was performed because the
+/// string was effectively empty.
+///
+/// \retval -STRTOX_NO_CONVERSION_PARSE No conversion was performed because the
+/// string did not parse as an integer.
+///
+/// \retval -STRTOX_INVALID_ARGUMENT No conversion was performed because the
+/// \a base specification was not valid.
+///
+/// \retval -STRTOX_UNDERFLOW_STRTOL1 Conversion resulted in underflow
+///
+/// \retval -STRTOX_UNDERFLOW_STRTOL2 Conversion resulted in underflow
+///
+/// \retval -STRTOX_UNDERFLOW_STRTOLL1 Conversion resulted in underflow
+///
+/// \retval -STRTOX_UNDERFLOW_STRTOLL2 Conversion resulted in underflow
+///
+/// \retval -STRTOX_OVERFLOW_STRTOL1 Conversion resulted in overflow
+///
+/// \retval -STRTOX_OVERFLOW_STRTOL2 Conversion resulted in overflow
+///
+/// \retval -STRTOX_OVERFLOW_STRTOLL1 Conversion resulted in overflow
+///
+/// \retval -STRTOX_OVERFLOW_STRTOLL2 Conversion resulted in overflow
+///
+
+#include "ssx.h"
+#include "ctype.h"
+#include "libssx.h"
+#include "strtox.h"
+
+
+// Skip whitespace
+
+static const char *
+skip_whitespace(const char *s)
+{
+ while (isspace(*s)) {
+ s++;
+ }
+ return s;
+}
+
+// Pick up a +/- sign. This is a predicate returning 1 if the value is
+// negated.
+
+static int
+sign(const char** s)
+{
+ if (**s == '+') {
+ (*s)++;
+ return 0;
+ } else if (**s == '-') {
+ (*s)++;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+// Look for a radix mark (0, 0[xX]). The string pointer is advanced if it is a
+// hex mark (0[xX]), but not for a simple '0' which could be either the start
+// of an octal constant or simply the number 0. The return value is either 8,
+// 10 or 16.
+
+static int
+radix_mark(const char** s)
+{
+ const char* p = *s;
+
+ if (p[0] == '0') {
+ if ((p[1] == 'x') || (p[1] == 'X')) {
+ *s += 2;
+ return 16;
+ } else {
+ return 8;
+ }
+ } else {
+ return 10;
+ }
+}
+
+
+// Parse a character as a radix-base digit. Return the value of the digit or
+// -1 if it is not a legal digit for the radix.
+
+static int
+parse_digit(char c, int radix)
+{
+ if (isdigit(c)) {
+ if ((c - '0') < radix) {
+ return c - '0';
+ } else {
+ return -1;
+ }
+ } else if (radix <= 10) {
+ return -1;
+ } else {
+ if (islower(c)) {
+ if ((c - 'a') < (radix - 10)) {
+ return c - 'a' + 10;
+ } else {
+ return -1;
+ }
+ } else if (isupper(c)) {
+ if ((c - 'A') < (radix - 10)) {
+ return c - 'A' + 10;
+ } else {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+ }
+}
+
+
+// The most basic API is strtox(), which converts a string to an unsigned long
+// long. All of the base APIs are written in terms of this. This is legal due
+// to the fact that conversion is defined to continue even in the event of
+// overflow. This API may return the codes STRTOX_NO_CONVERSION_EMPTY,
+// STRTOX_NO_CONVERSION_PARSE or STRTOX_INVALID_ARGUMENT,
+// which the standard APIs always convert to a 0
+// return value. Otherwise the flags 'overflow' and 'negative' are used by
+// the base APIs to determine how to handle special cases.
+
+static int
+strtox(const char *str, char **endptr, int base,
+ unsigned long long* value, int* negative, int* overflow)
+{
+ const char* s;
+ unsigned long long new;
+ int rc, radix, digit;
+
+
+ do {
+
+ s = str;
+ *value = 0;
+ *negative = 0;
+ *overflow = 0;
+
+ // Initial error checks
+
+ if ((base != 0) && ((base < 2) || (base > 36))) {
+ rc = STRTOX_INVALID_ARGUMENT;
+ break;
+ }
+
+ // Skip whitespace
+
+ s = skip_whitespace(s);
+ if (*s == '\0') {
+ rc = STRTOX_NO_CONVERSION_EMPTY;
+ break;
+ }
+
+ // Process a +/- sign. Only one is allowed.
+
+ *negative = sign(&s);
+
+ // Look for a radix mark. Note that if base == 16 this will cause the
+ // skip of a leading 0 in the string not followed by [xX], but that's
+ // OK because it doesn't change the result of the conversion.
+
+ if (base == 0) {
+ radix = radix_mark(&s);
+ } else {
+ radix = base;
+ if (radix == 16) {
+ radix_mark(&s);
+ }
+ }
+
+ // Parse. Note that once overflow is detected we continue to parse
+ // (but ignore the data).
+
+ rc = STRTOX_NO_CONVERSION_PARSE;
+
+ while ((digit = parse_digit(*s, radix)) >= 0) {
+ s++;
+ if (!*overflow) {
+ rc = 0;
+ new = (*value * radix) + digit;
+ if (new < *value) {
+ *overflow = 1;
+ } else {
+ *value = new;
+ }
+ }
+ }
+ } while(0);
+
+ if (endptr) {
+ if (rc == 0) {
+ *endptr = (char*)s;
+ } else {
+ *endptr = (char*)str;
+ }
+ }
+
+ return rc;
+}
+
+
+/// See documentation for the file strtox.c
+int
+_strtol(const char* str, char** endptr, int base, long* value)
+{
+ int rc, negative, overflow;
+ unsigned long long value_ull;
+
+ rc = strtox(str, endptr, base, &value_ull, &negative, &overflow);
+ if (rc) {
+ *value = 0;
+ } else {
+ if (overflow || (value_ull != (unsigned long)value_ull)) {
+ if (negative) {
+ rc = STRTOX_UNDERFLOW_STRTOL1;
+ *value = LONG_MIN;
+ } else {
+ rc = STRTOX_OVERFLOW_STRTOL1;
+ *value = LONG_MAX;
+ }
+ } else if (negative) {
+ if (value_ull > ((unsigned long long)LONG_MAX + 1ull)) {
+ rc = STRTOX_UNDERFLOW_STRTOL2;
+ *value = LONG_MIN;
+ } else {
+ *value = ~value_ull + 1;
+ }
+ } else if (value_ull > (unsigned long long)LONG_MAX) {
+ rc = STRTOX_OVERFLOW_STRTOL2;
+ *value = LONG_MAX;
+ } else {
+ *value = value_ull;
+ }
+ }
+ return rc;
+}
+
+
+/// See documentation for the file strtox.c
+int
+_strtoll(const char* str, char** endptr, int base, long long* value)
+{
+ int rc, negative, overflow;
+ unsigned long long value_ull;
+
+ rc = strtox(str, endptr, base, &value_ull, &negative, &overflow);
+ if (rc) {
+ *value = 0;
+ } else {
+ if (overflow) {
+ if (negative) {
+ rc = STRTOX_UNDERFLOW_STRTOLL1;
+ *value = LLONG_MIN;
+ } else {
+ rc = STRTOX_OVERFLOW_STRTOLL1;
+ *value = LLONG_MAX;
+ }
+ } else if (negative) {
+ if (value_ull > ((unsigned long long)LLONG_MAX + 1ull)) {
+ rc = STRTOX_UNDERFLOW_STRTOLL2;
+ *value = LLONG_MIN;
+ } else {
+ *value = ~value_ull + 1;
+ }
+ } else if (value_ull > (unsigned long long)LLONG_MAX) {
+ rc = STRTOX_OVERFLOW_STRTOLL2;
+ *value = LLONG_MAX;
+ } else {
+ *value = value_ull;
+ }
+ }
+ return rc;
+}
+
+
+/// See documentation for the file strtox.c
+int
+_strtoul(const char* str, char** endptr, int base, unsigned long* value)
+{
+ int rc, negative, overflow;
+ unsigned long long value_ull;
+
+ rc = strtox(str, endptr, base, &value_ull, &negative, &overflow);
+ if (rc) {
+ *value = 0;
+ } else {
+ if (overflow || (value_ull != (unsigned long)value_ull)) {
+ rc = STRTOX_OVERFLOW_STRTOUL;
+ *value = ULONG_MAX;
+ } else {
+ *value = value_ull;
+ if (negative) {
+ *value = ~*value + 1;
+ }
+ }
+ }
+ return rc;
+}
+
+/// See documentation for the file strtox.c
+int
+_strtoull(const char* str, char** endptr, int base, unsigned long long* value)
+{
+ int rc, negative, overflow;
+
+ rc = strtox(str, endptr, base, value, &negative, &overflow);
+ if (rc) {
+ *value = 0;
+ } else {
+ if (overflow) {
+ rc = STRTOX_OVERFLOW_STRTOULL;
+ *value = ULLONG_MAX;
+ } else {
+ if (negative) {
+ *value = ~*value + 1;
+ }
+ }
+ }
+ return rc;
+}
+
+
+/// See documentation for the file strtox.c
+long int
+strtol(const char* str, char** endptr, int base)
+{
+ long int value;
+
+ _strtol(str, endptr, base, &value);
+ return value;
+}
+
+
+/// See documentation for the file strtox.c
+long long int
+strtoll(const char* str, char** endptr, int base)
+{
+ long long int value;
+
+ _strtoll(str, endptr, base, &value);
+ return value;
+}
+
+
+/// See documentation for the file strtox.c
+unsigned long int
+strtoul(const char* str, char** endptr, int base)
+{
+ unsigned long int value;
+
+ _strtoul(str, endptr, base, &value);
+ return value;
+}
+
+
+/// See documentation for the file strtox.c
+unsigned long long int
+strtoull(const char* str, char** endptr, int base)
+{
+ unsigned long long int value;
+
+ _strtoull(str, endptr, base, &value);
+ return value;
+}
+
+
+#if (__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ <= 1))
+
+/// Internal version of strtol()
+///
+/// ppcnf-mcp5 (GCC 4.1) requires that the entry point __strtol_internal() be
+/// present at certain optimization levels. This is equivalent to strtol()
+/// except that it takes an extra argument that must be == 0. The \a group
+/// parameter is supposed to control locale-specific thousands grouping.
+
+long int
+__strtol_internal(const char* str, char** endptr, int base, int group)
+{
+ if (group != 0) {
+ SSX_PANIC(STRTOX_INVALID_ARGUMENT_STRTOL);
+ }
+ return strtol(str, endptr, base);
+}
+
+#endif
+
diff --git a/src/lib/ppc405lib/strtox.h b/src/lib/ppc405lib/strtox.h
new file mode 100644
index 0000000..db2cef2
--- /dev/null
+++ b/src/lib/ppc405lib/strtox.h
@@ -0,0 +1,151 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/strtox.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __STRTOX_H__
+#define __STRTOX_H__
+
+// $Id: strtox.h,v 1.2 2014/02/03 01:30:25 daviddu Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/strtox.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file strtox.h
+/// \brief Underlying and extended APIs that support strtoX macros
+///
+/// See the Doxygen comments of the file strtox.c for descriptions of the
+/// facilities provided by this header.
+
+#ifndef __ASSEMBLER__
+
+#include <limits.h>
+
+// Error codes
+
+#define STRTOX_NO_CONVERSION_EMPTY 0x00787901
+#define STRTOX_NO_CONVERSION_PARSE 0x00787902
+#define STRTOX_INVALID_ARGUMENT 0x00787903
+#define STRTOX_INVALID_ARGUMENT_STRTOL 0x00787904
+#define STRTOX_UNDERFLOW_STRTOL1 0x00787905
+#define STRTOX_UNDERFLOW_STRTOL2 0x00787906
+#define STRTOX_UNDERFLOW_STRTOLL1 0x00787907
+#define STRTOX_UNDERFLOW_STRTOLL2 0x00787908
+#define STRTOX_OVERFLOW_STRTOL1 0x00787909
+#define STRTOX_OVERFLOW_STRTOL2 0x0078790a
+#define STRTOX_OVERFLOW_STRTOLL1 0x0078790b
+#define STRTOX_OVERFLOW_STRTOLL2 0x0078790c
+#define STRTOX_OVERFLOW_STRTOUL 0x0078790d
+#define STRTOX_OVERFLOW_STRTOULL 0x0078790e
+
+// Earlier GCC configurations (ppcnf-mcp5-gcc) are not configured to define
+// these standard constants, which exist in the include tree under various
+// switches and configuration settings (from <limits.h>). They are defined by
+// default in later standard cross builds however (GCC 4.5, 4.6). However we
+// always assume that (long long) is a 64-bit type. It's likely that this is
+// the only place these constant will be used (as they are defined as the
+// values for under/overflow of strtoX() conversions), however it may be
+// necessary in the future to move these #defines somewhere else.
+
+#ifndef LLONG_MIN
+# define LLONG_MIN (0x8000000000000000ll)
+#endif
+
+#ifndef LLONG_MAX
+# define LLONG_MAX (0x7fffffffffffffffll)
+#endif
+
+#ifndef ULLONG_MAX
+# define ULLONG_MAX (0xffffffffffffffffull)
+#endif
+
+int
+_strtol(const char* str, char** endptr, int base, long* value);
+
+int
+_strtoul(const char* str, char** endptr, int base, unsigned long* value);
+
+int
+_strtoll(const char* str, char** endptr, int base, long long* value);
+
+int
+_strtoull(const char* str, char** endptr, int base, unsigned long long* value);
+
+
+// The way the sizeof(long) is discovered by default depends on which version
+// of gcc/cpp we're using as these macros are predefined by cpp.
+
+#if (__SIZEOF_LONG__ == 4) || (__LONG_MAX__ == 2147483647L)
+
+/// See documentation for the file strtox.c
+static inline int
+strtoi32(const char* str, char** endptr, int base, int32_t* value)
+{
+ long int value_l;
+ int rc;
+
+ rc = _strtol(str, endptr, base, &value_l);
+ *value = value_l;
+ return rc;
+}
+
+/// See documentation for the file strtox.c
+static inline int
+strtou32(const char* str, char** endptr, int base, uint32_t* value)
+{
+ unsigned long int value_ul;
+ int rc;
+
+ rc = _strtoul(str, endptr, base, &value_ul);
+ *value = value_ul;
+ return rc;
+}
+
+#else
+
+#error "No port of strtox.h yet for systems with sizeof(long) != 4"
+
+#endif
+
+// It is assumed that long long is always 64 bits; There is no standard macro
+// for this size constant
+
+/// See documentation for the file strtox.c
+static inline int
+strtoi64(const char* str, char** endptr, int base, int64_t* value)
+{
+ return _strtoll(str, endptr, base, value);
+}
+
+/// See documentation for the file strtox.c
+static inline int
+strtou64(const char* str, char** endptr, int base, uint64_t* value)
+{
+ return _strtoull(str, endptr, base, value);
+}
+
+#endif // __ASSEMBLER__
+
+#endif // __STRTOX_H__
diff --git a/src/lib/ppc405lib/sxlock.c b/src/lib/ppc405lib/sxlock.c
new file mode 100644
index 0000000..35f9698
--- /dev/null
+++ b/src/lib/ppc405lib/sxlock.c
@@ -0,0 +1,494 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/sxlock.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id$
+
+/// \file sxlock.c
+/// \brief API for the SharedExclusiveLock
+///
+/// The APIs in this file implement a shared-exclusive lock for SSX
+/// applications. This type of lock is also called a readers-writer lock. The
+/// lock is implemented in terms of SSX semaphores, so its use is limited to
+/// threads willing to block for access to a resource.
+///
+/// The SharedExclusiveLock allows multiple threads shared access to a
+/// resource, while limiting exclusive access to a single thread. There are
+/// several ways that this type of lock might be specified. The specification
+/// implemented here is an "exclusive-biasing" lock. As long as the lock is
+/// held or requested in exclusive mode, all new shared-mode requests will
+/// block, and only exclusive accesses will be allowed. If multiple threads
+/// are blocked exclusive the requests are honored in priority order (as
+/// the underlying implementation is an SSX semaphore). Once the exclusive
+/// lock is cleared, any/all threads blocked for shared access are released
+/// simultaneously (using an SSX semaphore as a thread barrier).
+///
+/// The lock is created (initialized) by sxlock_create(), which allows
+/// specification of an initial value of the number of shared or exclusive
+/// accesses outstanding. The lock/unlock APIs are as follows:
+///
+/// - sxlock_lock_shared(SharedExclusiveLock* sxlock, SsxInterval timeout)
+/// - sxlock_unlock_shared(SharedExclusiveLock* sxlock)
+/// - sxlock_lock_exclusive(SharedExclusiveLock* sxlock, SsxInterval timeout)
+/// - sxlock_unlock_exclusive(SharedExclusiveLock* sxlock)
+///
+/// Threads must always issue *_lock() and *_unlock() requests in matched
+/// pairs in order to avoid errors and deadlock. The *_lock() APIs allow
+/// specification of a timeout, which may be SSX_WAIT_FOREVER to indicate no
+/// timeout. The *_lock() APIs will return the code -SXLOCK_TIMED_OUT if the
+/// timeout occurs before the thread acquires the resource. If called from an
+/// interrupt context then the only legal timeout specification is
+/// SSX_NO_WAIT (0).
+///
+/// If a *_lock() request times out then the thread \e has \e not acquired the
+/// resource and \e must \e not call *_unlock(). As with semaphores there is
+/// no record that a thread holds a lock, so if a thread completes or is
+/// deleted while holding a lock it is likely that the application will
+/// deadlock.
+
+#include "ssx.h"
+#include "sxlock.h"
+
+/// Create (initialize) a SharedExclusiveLock
+///
+/// \param sxlock A pointer to the SharedExclusiveLock object to
+/// initialize
+///
+/// \param shared The initial numbers of shared accesses
+///
+/// \param exclusive The initial numbers of exclusive accesses
+///
+/// Create (initialize) a SharedExclusiveLock and optionally specify an
+/// initial state. The initial number of shared or exclusive accesses can be
+/// specified, however at most one of \a nshared and \a exclusive can be
+/// non-0. If \a shared or \a exclusive are non-0 then eventually a
+/// thread(s) will need to issue unmatched *_unlock() call(s) to allow
+/// progress for other threads requiring the resource.
+///
+/// \retval 0 Success
+///
+/// \retval SXLOCK_INVALID_OBJECT The \a sxlock parameter is NULL (0) or
+/// otherwise invalid.
+///
+/// \retval SXLOCK_INVALID_ARGUMENT Both of the \a shared and \a exclusive
+/// parameters are non-0.
+///
+/// \retval others sxlock_create() may also return codes from
+/// ssx_semaphore_create(), which would indicate a serious bug.
+
+int
+sxlock_create(SharedExclusiveLock* sxlock,
+ SsxSemaphoreCount shared,
+ SsxSemaphoreCount exclusive)
+{
+ int rc;
+
+ rc = 0;
+ do {
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(sxlock == 0,
+ SXLOCK_INVALID_OBJECT);
+ SSX_ERROR_IF((shared != 0) && (exclusive != 0),
+ SXLOCK_INVALID_ARGUMENT);
+ }
+
+ rc = ssx_semaphore_create(&(sxlock->shared_sem), 0, 0);
+ if (rc) break;
+
+ rc = ssx_semaphore_create(&(sxlock->exclusive_sem), 0, 0);
+ if (rc) break;
+
+ sxlock->running_shared = shared;
+ sxlock->running_exclusive = exclusive;
+
+ } while (0);
+
+ return rc;
+}
+
+
+/// Lock a SharedExclusiveLock for shared access
+///
+/// \param sxlock A pointer to the SharedExclusiveLock object to lock
+///
+/// \param timeout The maximum amount of time to wait for access, or the
+/// constant SSX_WAIT_FOREVER to wait forever.
+///
+/// Acquire a SharedExclusiveLock for shared access, potentially blocking
+/// forever or until a specified timeout if access is not immediately
+/// granted. Access will be blocked as long as one or more threads request or
+/// control exclusive acesss to the resource. Once the access is granted, the
+/// thread maintains shared access to the resource until a subsequent call of
+/// sxlock_unlock_shared().
+///
+/// Return values other than SSX_OK (0) are not necessarily errors; see \ref
+/// ssx_errors
+///
+/// The following return codes are non-error codes:
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SXLOCK_TIMED_OUT Shared access was not acquired before the
+/// timeout expired.
+///
+/// The following return codes are error codes:
+///
+/// \retval -SXLOCK_INVALID_OBJECT The \a sxlock parameter was NULL (0) or
+/// otherwise invalid.
+///
+/// \retval -SSX_ILLEGAL_CONTEXT The API was called from a critical
+/// interrupt context.
+///
+/// \retval -SSX_SEMAPHORE_PEND_WOULD_BLOCK The call was made from an
+/// interrupt context (or before threads have been started), shared access was
+/// not immediately available and a non-zero timeout was specified.
+///
+/// \retval others This API may also return codes from SSX semaphore APIs,
+/// which should be considered as non-recoverable errors.
+
+
+int
+sxlock_lock_shared(SharedExclusiveLock* sxlock, SsxInterval timeout)
+{
+ SsxMachineContext ctx;
+ int rc, pending_exclusive;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(sxlock == 0, SXLOCK_INVALID_OBJECT);
+ }
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ rc = 0;
+ do {
+
+ // NB: This is the only way to correctly compute the number of threads
+ // pending exclusive, given that threads could be removed from the
+ // exclusive_sem by timeout.
+
+ rc = ssx_semaphore_info_get(&(sxlock->exclusive_sem),
+ 0, &pending_exclusive);
+ if (rc) break;
+
+ if ((sxlock->running_exclusive == 0) && (pending_exclusive == 0)) {
+
+ // If no other thread has or is requesting exclusive access, the
+ // current thread gets immediate access.
+
+ sxlock->running_shared++;
+
+ } else {
+
+ // If threads are running or pending exclusive, this thread must
+ // pend shared. The thread will be unblocked by an exclusive
+ // unlock, which is responsible for adjusting
+ // sxlock->running_shared in this case.
+
+ rc = ssx_semaphore_pend(&(sxlock->shared_sem), timeout);
+ if (rc == -SSX_SEMAPHORE_PEND_TIMED_OUT) {
+ rc = -SXLOCK_TIMED_OUT;
+ }
+ }
+
+ } while (0);
+
+ ssx_critical_section_exit(&ctx);
+
+ return rc;
+}
+
+
+/// Relase a SharedExclusiveLock from shared access
+///
+/// \param sxlock A pointer to the SharedExclusiveLock object to unlock
+///
+/// Release a SharedExclusiveLock from shared access, signalling that the
+/// thread no longer requires or expects shared access to the resource. It is
+/// an error for a thread to use this API if it has not previously locked
+/// shared access by a call of sxlock_pend_shared() (or the thread is
+/// unlocking a lock initialized in the shared-locked state).
+///
+/// Return values other than SSX_OK (0) are errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SSX_ILLEGAL_CONTEXT The API was called from a critical interrupt
+/// context.
+///
+/// \retval -SXLOCK_INVALID_OBJECT The \a sxlock parameter was NULL (0) or
+/// otherwise invalid.
+///
+/// \retval -SXLOCK_SHARED_UNDERFLOW There was apparently no matched call of
+/// sxlock_lock_shared() prior to this call.
+///
+/// \retval others This API may also return codes from SSX semaphore APIs,
+/// which should be considered as non-recoverable errors.
+
+int
+sxlock_unlock_shared(SharedExclusiveLock* sxlock)
+{
+ SsxMachineContext ctx;
+ int rc, pending_exclusive;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF_CRITICAL_INTERRUPT_CONTEXT();
+ SSX_ERROR_IF(sxlock == 0, SXLOCK_INVALID_OBJECT);
+ SSX_ERROR_IF(sxlock->running_shared == 0, SXLOCK_SHARED_UNDERFLOW);
+ }
+
+ if (SSX_ERROR_CHECK_KERNEL) {
+ SSX_PANIC_IF(sxlock->running_exclusive != 0,
+ SXLOCK_SHARED_EXCLUSIVE_INVARIANT);
+ }
+
+ rc = 0;
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ do {
+
+ // If this is the last shared thread running, and a thread wants
+ // exclusive access, grant it. Note that there may be shared requests
+ // pending on the shared_sem but we always give preference to
+ // exclusive requests.
+
+ sxlock->running_shared--;
+ if (sxlock->running_shared == 0) {
+
+ // Wake any single thread pending exclusive
+
+ rc = ssx_semaphore_info_get(&(sxlock->exclusive_sem),
+ 0, &pending_exclusive);
+ if (rc) break;
+
+ if (pending_exclusive != 0) {
+
+ sxlock->running_exclusive = 1;
+ rc = ssx_semaphore_post(&(sxlock->exclusive_sem));
+ if (rc) break;
+ }
+ }
+
+ } while(0);
+
+ ssx_critical_section_exit(&ctx);
+
+ return rc;
+}
+
+
+/// Lock a SharedExclusiveLock for exclusive access
+///
+/// \param sxlock A pointer to the SharedExclusiveLock object to lock
+///
+/// \param timeout The maximum amount of time to wait for access, or the
+/// constant SSX_WAIT_FOREVER to wait forever.
+///
+/// Acquire a SharedExclusiveLock for exclusive access, potentially blocking
+/// forever or until a specified timeout if access is not immediately
+/// granted. Access will be blocked as long as one or more threads control
+/// shared acesss to the resource, however once the thread requests exclusive
+/// access all new shared access requests will block. Once the access is
+/// granted, the thread maintains exclusive access to the resource until a
+/// subsequent call of sxlock_unlock_exclusive().
+///
+/// Return values other than SSX_OK (0) are not necessarily errors; see \ref
+/// ssx_errors
+///
+/// The following return codes are non-error codes:
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SXLOCK_TIMED_OUT Exclusive access was not acquired before the
+/// timeout expired.
+///
+/// The following return codes are error codes:
+///
+/// \retval -SXLOCK_INVALID_OBJECT The \a sxlock parameter was NULL (0) or
+/// otherwise invalid.
+///
+/// \retval -SSX_ILLEGAL_CONTEXT The API was called from a critical
+/// interrupt context.
+///
+/// \retval -SSX_SEMAPHORE_PEND_WOULD_BLOCK The call was made from an
+/// interrupt context (or before threads have been started), exclusive access
+/// was not immediately available and a non-zero timeout was specified.
+///
+/// \retval others This API may also return codes from SSX semaphore APIs,
+/// which shoudl be considered as non-recoverable errors.
+
+
+int
+sxlock_lock_exclusive(SharedExclusiveLock* sxlock, SsxInterval timeout)
+{
+ SsxMachineContext ctx;
+ int rc, pending_exclusive, pending_shared;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(sxlock == 0, SXLOCK_INVALID_OBJECT);
+ }
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ rc = 0;
+ do {
+
+ if ((sxlock->running_shared == 0) &&
+ (sxlock->running_exclusive == 0)) {
+
+ // If no other thread has acquired the lock, this thread gets
+ // immediate access.
+
+ sxlock->running_exclusive = 1;
+
+ } else {
+
+ // Some other thread has acquired the lock. This thread must pend
+ // exclusive. In this case the sxlock->running_exclusive must be
+ // set by the *_unlock() operation that unblocks the thread.
+
+ rc = ssx_semaphore_pend(&(sxlock->exclusive_sem), timeout);
+ if (rc == -SSX_SEMAPHORE_PEND_TIMED_OUT) {
+
+ // This exclusive request timed out. Since the request may
+ // have blocked shared requests, then if this is the only
+ // exclusive request or thread we need to unblock any pending
+ // shared requests.
+
+ if (sxlock->running_exclusive == 0) {
+
+ rc = ssx_semaphore_info_get(&(sxlock->exclusive_sem),
+ 0, &pending_exclusive);
+ if (rc) break;
+
+ if (pending_exclusive == 0) {
+
+ rc = ssx_semaphore_info_get(&(sxlock->shared_sem),
+ 0, &pending_shared);
+ if (rc) break;
+
+ if (pending_shared != 0) {
+
+ sxlock->running_shared += pending_shared;
+ rc = ssx_semaphore_release_all(&(sxlock->shared_sem));
+ if (rc) break;
+ }
+ }
+ }
+
+ rc = -SXLOCK_TIMED_OUT;
+ }
+ }
+
+ } while (0);
+
+ ssx_critical_section_exit(&ctx);
+
+ return rc;
+}
+
+
+/// Release a SharedExclusiveLock from exclusive access
+///
+/// \param sxlock A pointer to the SharedExclusiveLock object to unlock
+///
+/// Release a SharedExclusiveLock from exclusive access, signalling that the
+/// thread no longer requires or expects exclusive access to the resource. It
+/// is an error for a thread to use this API if it has not previously locked
+/// exclusive access by a call of sxlock_lock_exclusive() (or the thread is
+/// unlocking a lock initialized in the exclusive-locked state).
+///
+/// Return values other than SSX_OK (0) are errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SSX_ILLEGAL_CONTEXT The API was called from a critical interrupt
+/// context.
+///
+/// \retval -SXLOCK_INVALID_OBJECT The \a sxlock parameter was NULL (0) or
+/// otherwise invalid.
+///
+/// \retval -SXLOCK_EXCLUSIVE_UNDERFLOW There was apparently no matched call of
+/// sxlock_lock_exclusive() prior to this call.
+///
+/// \retval others This API may also return codes from SSX semaphore APIs,
+/// which should be considered as non-recoverable errors.
+
+int
+sxlock_unlock_exclusive(SharedExclusiveLock* sxlock)
+{
+ SsxMachineContext ctx;
+ int rc, pending_exclusive, pending_shared;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF_CRITICAL_INTERRUPT_CONTEXT();
+ SSX_ERROR_IF(sxlock == 0, SXLOCK_INVALID_OBJECT);
+ SSX_ERROR_IF(sxlock->running_exclusive != 1, SXLOCK_SHARED_UNDERFLOW);
+ }
+
+ if (SSX_ERROR_CHECK_KERNEL) {
+ SSX_PANIC_IF(sxlock->running_shared != 0,
+ SXLOCK_SHARED_EXCLUSIVE_INVARIANT);
+ }
+
+ rc = 0;
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ do {
+
+ rc = ssx_semaphore_info_get(&(sxlock->exclusive_sem),
+ 0, &pending_exclusive);
+ if (rc) break;
+
+ if (pending_exclusive != 0) {
+
+ // If there are other threads pending exclusive, make the
+ // highest-priority one of them
+ // runnable. sxlock->running_exclusive remains equal to 1.
+
+ rc = ssx_semaphore_post(&(sxlock->exclusive_sem));
+ if (rc) break;
+
+ } else {
+
+ // Otherwise unblock any/all threads pending shared
+
+ sxlock->running_exclusive = 0;
+
+ rc = ssx_semaphore_info_get(&(sxlock->shared_sem),
+ 0, &pending_shared);
+ if (rc) break;
+
+ if (pending_shared != 0) {
+
+ sxlock->running_shared = pending_shared;
+ rc = ssx_semaphore_release_all(&(sxlock->shared_sem));
+ if (rc) break;
+ }
+ }
+ } while (0);
+
+ ssx_critical_section_exit(&ctx);
+
+ return rc;
+}
diff --git a/src/lib/ppc405lib/sxlock.h b/src/lib/ppc405lib/sxlock.h
new file mode 100644
index 0000000..e0fa196
--- /dev/null
+++ b/src/lib/ppc405lib/sxlock.h
@@ -0,0 +1,108 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/sxlock.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __SXLOCK_H__
+#define __SXLOCK_H__
+
+// $Id$
+
+/// \file sxlock.h
+/// \brief The implementation of a SharedExclusiveLock
+///
+/// The SharedExclusiveLock is documented in the comments for the file
+/// sxlock.c
+
+// Error/panic codes
+
+#define SXLOCK_INVALID_OBJECT 0x00795501
+#define SXLOCK_INVALID_ARGUMENT 0x00795502
+#define SXLOCK_TIMED_OUT 0x00795503
+#define SXLOCK_SHARED_UNDERFLOW 0x00795504
+#define SXLOCK_EXCLUSIVE_UNDERFLOW 0x00795505
+#define SXLOCK_SHARED_EXCLUSIVE_INVARIANT 0x00795506
+
+/// A shared-exclusive lock object (also called a readers-write lock)
+///
+/// This facility is documented in the file sxlock.c
+
+typedef struct {
+
+ /// A semaphore for threads requesting shared access
+ SsxSemaphore shared_sem;
+
+ /// A semaphore for threads requesting exclusive access
+ SsxSemaphore exclusive_sem;
+
+ /// The number of threads running shared
+ SsxSemaphoreCount running_shared;
+
+ /// The number of threads running exclusive
+ SsxSemaphoreCount running_exclusive;
+
+} SharedExclusiveLock;
+
+
+/// Static initialization of a shared-exclusive lock object
+///
+/// \param[in] shared The number of threads running shared at static
+/// initialization
+///
+/// \param[in] exclusive The number of threads running exclusive at static
+/// initialization.
+///
+/// Note that it is an error to specify both \a shared and \a exclusive as
+/// non-0.
+
+#define SXLOCK_INITIALIZATION(shared, exclusive) \
+ { \
+ SSX_SEMAPHORE_INITIALIZATION(0, 0), \
+ SSX_SEMAPHORE_INITIALIZATION(0, 0), \
+ (shared), (exclusive) \
+ }
+
+/// Declare and initialize a shared-exclusive lock
+
+#define SXLOCK(sxlock, shared, exclusive) \
+ SharedExclusiveLock sxlock = SXLOCK_INITIALIZATION(shared, exclusive)
+
+
+
+int
+sxlock_create(SharedExclusiveLock* sxlock,
+ SsxSemaphoreCount shared,
+ SsxSemaphoreCount exclusive);
+
+int
+sxlock_lock_shared(SharedExclusiveLock* sxlock, SsxInterval timeout);
+
+int
+sxlock_unlock_shared(SharedExclusiveLock* sxlock);
+
+int
+sxlock_lock_exclusive(SharedExclusiveLock* sxlock, SsxInterval timeout);
+
+int
+sxlock_unlock_exclusive(SharedExclusiveLock* sxlock);
+
+#endif // __SXLOCK_H__
diff --git a/src/lib/ppc405lib/time.c b/src/lib/ppc405lib/time.c
new file mode 100644
index 0000000..39d005c
--- /dev/null
+++ b/src/lib/ppc405lib/time.c
@@ -0,0 +1,82 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/ppc405lib/time.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: time.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/time.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file time.c
+/// \brief Implementation of functions from <time.h>
+///
+/// The following standard APIs are currently supported:
+///
+/// - clock_gettime() with the single clock id CLOCK_REALTIME
+///
+/// Since SSX does not currently have any per-thread CPU time statistics, we
+/// can not implement process-CPU-time-based APIs like the simple clock() or
+/// clock_gettime() with CLOCK_REALTIME.
+
+#include "ssx.h"
+#include <errno.h>
+#include <time.h>
+
+/// Get time from a timer
+///
+/// \param clock_id This must be the constant CLOCK_REALTIME defined in
+/// <time.h>.
+///
+/// \param tp A pointer to a struct timespec populated by this API.
+///
+/// Although the Posix standard requires that clock_gettime() support
+/// CLOCK_REALTIME, CLOCK_REALTIME measures standard Unix time (seconds since
+/// the epoch) which is not available to SSX. SSX currently only supports
+/// CLOCK_MONOTONIC, which is derived from the SSX timebase.
+///
+/// \returns Either 0 for success, or -EINVAL in the event of an invalid
+/// argument (unrecognized \a clock_id, NULL \a tp pointer).
+
+int
+clock_gettime(clockid_t clock_id, struct timespec* tp)
+{
+ int rc;
+ SsxTimebase now;
+
+ if ((clock_id != CLOCK_MONOTONIC) || (tp == 0)) {
+ rc = -EINVAL;
+ } else {
+
+ now = ssx_timebase_get();
+ tp->tv_sec = now / SSX_TIMEBASE_FREQUENCY_HZ;
+ tp->tv_nsec =
+ ((now % SSX_TIMEBASE_FREQUENCY_HZ) * 1000000000) /
+ SSX_TIMEBASE_FREQUENCY_HZ;
+ rc = 0;
+ }
+
+ return rc;
+}
OpenPOWER on IntegriCloud