summaryrefslogtreecommitdiffstats
path: root/src/ssx/ssx
diff options
context:
space:
mode:
Diffstat (limited to 'src/ssx/ssx')
-rwxr-xr-xsrc/ssx/ssx/Makefile25
-rwxr-xr-xsrc/ssx/ssx/ssx.h126
-rwxr-xr-xsrc/ssx/ssx/ssx_api.h888
-rwxr-xr-xsrc/ssx/ssx/ssx_core.c81
-rwxr-xr-xsrc/ssx/ssx/ssx_init.c159
-rwxr-xr-xsrc/ssx/ssx/ssx_kernel.h281
-rwxr-xr-xsrc/ssx/ssx/ssx_macros.h119
-rwxr-xr-xsrc/ssx/ssx/ssx_semaphore_core.c331
-rwxr-xr-xsrc/ssx/ssx/ssx_semaphore_init.c84
-rwxr-xr-xsrc/ssx/ssx/ssx_stack_init.c87
-rwxr-xr-xsrc/ssx/ssx/ssx_thread_core.c946
-rwxr-xr-xsrc/ssx/ssx/ssx_thread_init.c140
-rwxr-xr-xsrc/ssx/ssx/ssx_timer_core.c447
-rwxr-xr-xsrc/ssx/ssx/ssx_timer_init.c124
-rwxr-xr-xsrc/ssx/ssx/ssxssxfiles.mk35
15 files changed, 3873 insertions, 0 deletions
diff --git a/src/ssx/ssx/Makefile b/src/ssx/ssx/Makefile
new file mode 100755
index 0000000..ce1116f
--- /dev/null
+++ b/src/ssx/ssx/Makefile
@@ -0,0 +1,25 @@
+# $Id: Makefile,v 1.2 2013/12/12 16:12:38 bcbrock Exp $
+
+# This Makefile is designed to be invoked with the -I argument set to
+# the location of the "ssx.mk" for the build
+
+include ../pgp/ssx.mk
+include ssxssxfiles.mk
+
+ifeq "$(SSX_TIMER_SUPPORT)" "1"
+SSX_OBJECTS += ${SSX-TIMER-C-SOURCES:.c=.o}
+endif
+
+ifeq "$(SSX_THREAD_SUPPORT)" "1"
+SSX_OBJECTS += ${SSX-THREAD-C-SOURCES:.c=.o}
+endif
+
+all: $(SSX_OBJECTS)
+
+.PHONY : clean
+clean:
+ rm -f *.o *.d *.d.*
+
+ifneq ($(MAKECMDGOALS),clean)
+include $(SSX_OBJECTS:.o=.d)
+endif
diff --git a/src/ssx/ssx/ssx.h b/src/ssx/ssx/ssx.h
new file mode 100755
index 0000000..5470968
--- /dev/null
+++ b/src/ssx/ssx/ssx.h
@@ -0,0 +1,126 @@
+#ifndef __SSX_H__
+#define __SSX_H__
+
+// $Id: ssx.h,v 1.1.1.1 2013/12/11 21:03:27 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ssx/ssx/ssx.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ssx.h
+/// \brief The combined header of the SSX kernel.
+///
+/// This header will be included in any C or assembler source file that
+/// requires any of the SSX API. All headers defined by SSX and co-compiled
+/// code should be protected such that they can be included without error into
+/// assembly.
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+#include <stddef.h>
+#endif /* __ASSEMBLER__ */
+
+#define __SSX__
+
+/// The application environment specifies whether or not it will provide an
+/// application configuration file, which must be named "ssx_app_cfg.h".
+
+#ifndef USE_SSX_APP_CFG_H
+#define USE_SSX_APP_CFG_H 0
+#endif
+
+#if USE_SSX_APP_CFG_H
+#include "ssx_app_cfg.h"
+#endif
+
+#include "ssx_macros.h"
+#include "ssx_api.h"
+#include "ssx_port.h"
+#include "ssx_kernel.h"
+#include "ssx_io.h"
+
+#ifndef __ASSEMBLER__
+
+#define MIN(X, Y) \
+ ({ \
+ typeof (X) __x = (X); \
+ typeof (Y) __y = (Y); \
+ (__x < __y) ? __x : __y; })
+
+#define MAX(X, Y) \
+ ({ \
+ typeof (X) __x = (X); \
+ typeof (Y) __y = (Y); \
+ (__x > __y) ? __x : __y; \
+ })
+
+/// \todo These don't require 32/64 bit versions, can always promote 32->64.
+
+#define FLOOR_LOG2_32(x) (32 - 1 - cntlz32(x))
+#define FLOOR_LOG2_64(x) (64 - 1 - cntlz64(x))
+
+#define CEILING_LOG2(x) \
+ ({ \
+ uint64_t __x = (uint64_t)(x); \
+ int __y; \
+ __y = FLOOR_LOG2_64(__x); \
+ if ((__x & (__x - 1)) != 0) { \
+ __y++; \
+ } \
+ __y;})
+
+
+#define POW2_32(x) ((uint32_t)1 << (x))
+#define POW2_64(x) ((uint64_t)1 << (x))
+
+/// Cast a pointer to another type
+///
+/// This macro is necessary when casting a pointer to a longer integer type.
+/// The pointer is first cast to the equivalent integer type 'unsigned long',
+/// then cast to the final type. You can also use this to cast integers longer
+/// than pointers back to pointers.
+
+#define CAST_POINTER(t, p) ((t)((unsigned long)(p)))
+
+
+/// Create an alignment attribute.
+#define ALIGNED_ATTRIBUTE(alignment) __attribute__ ((aligned (alignment)))
+
+/// Create a specific-section attribute
+///
+/// Note that the section \a s here must be a string. Also note that data
+/// specified to reside in specific sections must always be
+/// initialized. Otherwise it confuses the linker which wants to put
+/// uninitialized data into .bss sections.
+///
+/// \code
+///
+/// int foo SECTION_ATTRIBUTE(".noncacheable") = 0;
+/// int bar[10] SECTION_ATTRIBUTE(".noncacheable") = {0};
+///
+/// \endcode
+#define SECTION_ATTRIBUTE(s) __attribute__ ((section (s)))
+
+/// Create a 'used' attribute
+///
+/// This is required for example to avoid "function unused" warnings when a
+/// function is declared static but only referenced by inline assembler:
+///
+/// \code
+///
+/// static USED_ATTRIBUTE void
+/// _checkstop(void* arg, SsxIrqId irq, int priority)
+/// {
+/// SSX_PANIC(VALIDATION_CHECKSTOP);
+/// }
+///
+/// SSX_IRQ_FAST2FULL(_validationCheckstopHandler, _checkstop);
+///
+/// \endcode
+#define USED_ATTRIBUTE __attribute__ ((used))
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* __SSX_H__ */
diff --git a/src/ssx/ssx/ssx_api.h b/src/ssx/ssx/ssx_api.h
new file mode 100755
index 0000000..c9657e4
--- /dev/null
+++ b/src/ssx/ssx/ssx_api.h
@@ -0,0 +1,888 @@
+#ifndef __SSX_API_H__
+#define __SSX_API_H__
+
+// $Id: ssx_api.h,v 1.2 2014/02/03 01:30:44 daviddu Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ssx/ssx/ssx_api.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ssx_api.h
+/// \brief Macros and declarations for the SSX API.
+
+// Basic constants
+
+/// Although the number of threads is defined as a manifest constant,
+/// numerous parts of the SSX code assume this definition. The number of
+/// supported threads _can not_ be changed simply by changing this constant.
+
+#define SSX_THREADS 32
+
+#define SSX_IDLE_THREAD_PRIORITY SSX_THREADS
+
+// Interrupt API
+
+#define SSX_NONCRITICAL 0
+#define SSX_CRITICAL 1
+#define SSX_SUPERCRITICAL 2
+
+#define SSX_IRQ_POLARITY_ACTIVE_LOW 0
+#define SSX_IRQ_POLARITY_ACTIVE_HIGH 1
+
+#define SSX_IRQ_TRIGGER_LEVEL_SENSITIVE 0
+#define SSX_IRQ_TRIGGER_EDGE_SENSITIVE 1
+
+// API return codes
+
+#define SSX_OK 0
+#define SSX_ILLEGAL_CONTEXT_CRITICAL_INTERRUPT 0x00779001
+#define SSX_ILLEGAL_CONTEXT_THREAD_CONTEXT 0x00779002
+#define SSX_ILLEGAL_CONTEXT_INTERRUPT_CONTEXT 0x00779003
+#define SSX_ILLEGAL_CONTEXT_THREAD 0x00779004
+#define SSX_ILLEGAL_CONTEXT_TIMER 0x00779005
+#define SSX_ILLEGAL_CONTEXT_PPC405_CACHE 0x00779006
+#define SSX_INVALID_THREAD_AT_RESUME1 0x00779007
+#define SSX_INVALID_THREAD_AT_RESUME2 0x00779008
+#define SSX_INVALID_THREAD_AT_SUSPEND1 0x00779009
+#define SSX_INVALID_THREAD_AT_SUSPEND2 0x0077900a
+#define SSX_INVALID_THREAD_AT_DELETE 0x0077900b
+#define SSX_INVALID_THREAD_AT_INFO 0x0077900c
+#define SSX_INVALID_THREAD_AT_CHANGE 0x0077900d
+#define SSX_INVALID_THREAD_AT_SWAP1 0x0077900e
+#define SSX_INVALID_THREAD_AT_SWAP2 0x0077900f
+#define SSX_INVALID_THREAD_AT_CREATE 0x00779010
+#define SSX_INVALID_SEMAPHORE_AT_POST 0x00779011
+#define SSX_INVALID_SEMAPHORE_AT_PEND 0x00779012
+#define SSX_INVALID_SEMAPHORE_AT_RELEASE 0x00779013
+#define SSX_INVALID_SEMAPHORE_AT_INFO 0x00779014
+#define SSX_INVALID_SEMAPHORE_AT_CREATE 0x00779015
+#define SSX_INVALID_TIMER_AT_SCHEDULE 0x00779016
+#define SSX_INVALID_TIMER_AT_CANCEL 0x00779017
+#define SSX_INVALID_TIMER_AT_INFO 0x00779018
+#define SSX_INVALID_TIMER_AT_CREATE 0x00779019
+#define SSX_INVALID_ARGUMENT_IRQ_SETUP 0x0077901a
+#define SSX_INVALID_ARGUMENT_IRQ_HANDLER 0x0077901b
+#define SSX_INVALID_ARGUMENT_INTERRUPT 0x00779024
+#define SSX_INVALID_ARGUMENT_CONTEXT_SET 0x00779025
+#define SSX_INVALID_ARGUMENT_CONTEXT_GET 0x00779026
+#define SSX_INVALID_ARGUMENT_PPC405_FIT 0x00779027
+#define SSX_INVALID_ARGUMENT_PPC405_WATCHDOG 0x00779028
+#define SSX_INVALID_ARGUMENT_INIT 0x00779029
+#define SSX_INVALID_ARGUMENT_SEMAPHORE 0x0077902a
+#define SSX_INVALID_ARGUMENT_THREAD_CHANGE 0x0077902b
+#define SSX_INVALID_ARGUMENT_THREAD_PRIORITY 0x0077902c
+#define SSX_INVALID_ARGUMENT_THREAD1 0x0077902d
+#define SSX_INVALID_ARGUMENT_THREAD2 0x0077902e
+#define SSX_INVALID_ARGUMENT_THREAD3 0x0077902f
+#define SSX_STACK_OVERFLOW 0x00779030
+#define SSX_TIMER_ACTIVE 0x00779031
+#define SSX_TIMER_NOT_ACTIVE 0x00779032
+#define SSX_PRIORITY_IN_USE_AT_RESUME 0x00779033
+#define SSX_PRIORITY_IN_USE_AT_CHANGE 0x00779034
+#define SSX_PRIORITY_IN_USE_AT_SWAP 0x00779035
+#define SSX_SEMAPHORE_OVERFLOW 0x00779036
+#define SSX_SEMAPHORE_PEND_NO_WAIT 0x00779037
+#define SSX_SEMAPHORE_PEND_TIMED_OUT 0x00779038
+#define SSX_SEMAPHORE_PEND_WOULD_BLOCK 0x00779039
+#define SSX_INVALID_DEQUE_SENTINEL 0x0077903a
+#define SSX_INVALID_DEQUE_ELEMENT 0x0077903b
+#define SSX_INVALID_OBJECT 0x0077903c
+
+// Kernel panics
+
+#define SSX_NO_TIMER_SUPPORT 0x0077903d
+#define SSX_START_THREADS_RETURNED 0x0077903e
+#define SSX_UNIMPLEMENTED 0x0077903f
+#define SSX_SCHEDULING_INVARIANT 0x00779040
+#define SSX_TIMER_HANDLER_INVARIANT 0x00779041
+#define SSX_THREAD_TIMEOUT_STATE 0x00779045
+
+
+/// \defgroup ssx_thread_states SSX Thread States
+///
+/// Threads are created in the state SSX_THREAD_STATE_SUSPENDED_RUNNABLE.
+/// When the thread is mapped it transitions to state SSX_THREAD_STATE_MAPPED.
+/// A mapped thread is runnable if it appears in the run queue; there is no
+/// other flag or status to indicate a runnable thread. If a blocked thread
+/// is suspended it goes into state SSX_THREAD_STATE_SUSPENDED_BLOCKED. For
+/// all threads the reason for blockage is detailed in the \a flags field of
+/// the thread; See \ref ssx_thread_flags. SSX_THREAD_STATE_DELETED and
+/// SSX_THREAD_STATE_COMPLETED are effectively equivalent but named
+/// individually for reporting purposes.
+///
+/// \note This separation of the thread \a state and \a flags allows the use
+/// of an SSX semaphore as a thread barrier, as it supports a non-iterative
+/// implementation of ssx_semaphore_release_all() in which all threads blocked
+/// on the semaphore are simultaneously inserted into the run queue with an
+/// atomic operation, followed by each individual thread readjusting its flags
+/// appropriately once the thread runs again.
+///
+/// @{
+
+#define SSX_THREAD_STATE_SUSPENDED_RUNNABLE 1
+#define SSX_THREAD_STATE_MAPPED 2
+#define SSX_THREAD_STATE_SUSPENDED_BLOCKED 3
+#define SSX_THREAD_STATE_COMPLETED 4
+#define SSX_THREAD_STATE_DELETED 5
+
+/// @}
+
+
+/// \defgroup ssx_thread_flags SSX Thread Flags
+///
+/// The \a flag field of the thread extends the information contained in the
+/// \a state field; See \ref ssx_thread_states. Blocked threads will show
+/// SSX_THREAD_FLAG_SEMAPHORE_PEND, SSX_THREAD_FLAG_TIMER_PEND or both (if
+/// blocked on a semaphore with timeout). The flag SSX_THREAD_FLAG_TIMED_OUT
+/// indicates that a thread timer timed out before the thread became
+/// runnable. Currently only the semaphore-pend-with-timeout code uses this
+/// flag.
+///
+/// Note that a thread can be mapped and runnable (in the run queue) even
+/// though SSX_THREAD_FLAG_SEMAPHORE_PEND and/or SSX_THREAD_FLAG_TIMER_PEND
+/// are set. These flags are always cleared by the thread itself, not the code
+/// that unblocks the thread. This allows the implementation of the
+/// ssx_semaphore_release_all() as explained in \ref ssx_thread_states.
+///
+/// @{
+
+#define SSX_THREAD_FLAG_SEMAPHORE_PEND 0x1
+#define SSX_THREAD_FLAG_TIMER_PEND 0x2
+#define SSX_THREAD_FLAG_TIMED_OUT 0x4
+
+/// @}
+
+
+// Critical Sections
+
+/// Enter a critical section of a given priority, saving the current machine
+/// context.
+
+#define ssx_critical_section_enter(priority, pctx) \
+ ssx_interrupt_disable(priority, pctx)
+
+/// Exit a critical section by restoring the previous machine context.
+
+#define ssx_critical_section_exit(pctx) \
+ ssx_machine_context_set(pctx)
+
+
+/// Execute a statement atomically, in a particular interrupt priority
+/// context.
+
+#define SSX_ATOMIC(priority, stmt) \
+ do { \
+ SsxMachineContext __ctx; \
+ ssx_critical_section_enter((priority), &__ctx); \
+ stmt; \
+ ssx_critical_section_exit(&__ctx); \
+ } while (0)
+
+
+// Application-overrideable definitions
+
+/// Control whether or not the API functions check for errors.
+///
+/// This definition can be overriden by the application.
+
+#ifndef SSX_ERROR_CHECK_API
+#define SSX_ERROR_CHECK_API 1
+#endif
+
+/// Control whether API errors cause kernel panics or return negative error
+/// codes.
+///
+/// This selection is only valid if \c SSX_ERROR_CHECK_API is defined
+/// non-0. This definition can be overriden by the application.
+
+#ifndef SSX_ERROR_PANIC
+#define SSX_ERROR_PANIC 1
+#endif
+
+/// Control whether or not the SSX kernel checks key invariants.
+///
+/// Violations of kernel invariants always cause kernel panics. This
+/// definition can be overriden by the application.
+
+#ifndef SSX_ERROR_CHECK_KERNEL
+#define SSX_ERROR_CHECK_KERNEL 1
+#endif
+
+/// Define the time interval type, which must be an unsigned type of a size
+/// less then or equal to the size of \c SsxTimebase. This definition can be
+/// overridden by the application.
+
+#ifndef SSX_TIME_INTERVAL_TYPE
+#define SSX_TIME_INTERVAL_TYPE uint32_t
+#endif
+
+/// Provide support for the SsxTimer APIs in addition to the default
+/// initerrupt APIs. This definition can be overridden by the application.
+
+#ifndef SSX_TIMER_SUPPORT
+#define SSX_TIMER_SUPPORT 1
+#endif
+
+/// Provide support for the all SSX APIs. Thread support requires/implies
+/// support for time services and semaphores. This definition can be
+/// overridden by the application.
+
+#ifndef SSX_THREAD_SUPPORT
+#define SSX_THREAD_SUPPORT 1
+#endif
+
+/// Control the level of stack checking.
+///
+/// This definition can be overriden by the application.
+///
+/// 0 : No stack prepatterning or checking is made for thread and kernel
+/// stacks.
+///
+/// 1 : Kernel interrupt stacks are prepatterned during
+/// \c ssx_initialize(). Thread stacks are prepatterned during
+/// \c ssx_thread_create().
+///
+/// 2 : (\b Default - Currently Unimplemented) In addition to prepatterning,
+/// stack utilization is computed at the exit of context switches and
+/// noncritical interrupt processing. The maximum utilization is stored in
+/// the thread data structure. The kernel will panic if stack overflow is
+/// detected. Stack utilization is not computed for the idle thread.
+
+#ifndef SSX_STACK_CHECK
+#define SSX_STACK_CHECK 1
+#endif
+
+/// A hook for main()
+///
+/// This hook macro is expanded in the body of __ssx_main() prior to the call
+/// of the application main(). The application can redefine this hook macro
+/// in (or in headers referred to in) the application header
+/// ssx_app_cfg.h. The SSX_MAIN_HOOK will run on the stack of main().
+
+#ifndef SSX_MAIN_HOOK
+#define SSX_MAIN_HOOK do {} while (0)
+#endif
+
+/// A hook for ssx_start_threads()
+///
+/// This hook macro is expanded in the call-tree of ssx_start_threads() before
+/// threads are actually started. The application can redefine this hook
+/// macro in (or in headers referred to in) the application header
+/// ssx_app_cfg.h.
+///
+/// The SSX_START_THREADS_HOOK runs as a pseudo-interrupt handler on the
+/// noncritical interrupt stack, with noncritical interrupts disabled.
+
+#ifndef SSX_START_THREADS_HOOK
+#define SSX_START_THREADS_HOOK do {} while (0)
+#endif
+
+/// The maximum value of the \c SsxTimebase type.
+
+#define SSX_TIMEBASE_MAX ((SsxTimebase)-1)
+
+/// A special value that specifies that the timebase will not be reset during
+/// ssx_init().
+
+#define SSX_TIMEBASE_CONTINUES SSX_TIMEBASE_MAX
+
+/// By convention, a timeout value indicating 'no waiting' in a call of \c
+/// ssx_semaphore_pend().
+
+#define SSX_NO_WAIT 0
+
+/// By convention, a timeout value indicating 'wait forever' in a call of \c
+/// ssx_semaphore_pend().
+
+#define SSX_WAIT_FOREVER ((SsxInterval)-1)
+
+/// The SSX timebase frequency in Hz
+///
+/// Earlier version of SSX defined the timbase frequency as a preprocessor
+/// macro. Now, the timebase frequency is specified as a parameter of the
+/// ssx_initialize() API. The macro remains defined for backwards
+/// compatibility, however all kernel uses of the timebase frequency are now
+/// optimized around the timebase parameter.
+
+#define SSX_TIMEBASE_FREQUENCY_HZ __ssx_timebase_frequency_hz
+
+/// Convert a time in integral seconds to a time interval - overflows are
+/// ignored. The application can redefine this macro.
+
+#ifndef SSX_SECONDS
+#define SSX_SECONDS(s) ((SsxInterval)(__ssx_timebase_frequency_hz * (SsxInterval)(s)))
+#endif
+
+/// Convert a time in integral milliseconds to a time interval - overflows are
+/// ignored, and a frequency evenly (or closely) divisible by 1000 is
+/// assumed. The application can redefine this macro.
+
+#ifndef SSX_MILLISECONDS
+#define SSX_MILLISECONDS(m) ((SsxInterval)(__ssx_timebase_frequency_khz * (SsxInterval)(m)))
+#endif
+
+/// Convert a time in integral microseconds to a time interval - overflows are
+/// ignored, and a frequncy evenly (or closely) divisible by 1,000,000 is
+/// assumed. The application can redefine this macro.
+
+#ifndef SSX_MICROSECONDS
+#define SSX_MICROSECONDS(u) ((SsxInterval)(__ssx_timebase_frequency_mhz * (SsxInterval)(u)))
+#endif
+
+/// Convert a time in integral nanoseconds to a time interval - overflows are
+/// ignored, and a frequeyncy evenly (or closely) divisible by 1,000,000 is
+/// assumed. The application can redefine this macro.
+
+#ifndef SSX_NANOSECONDS
+#define SSX_NANOSECONDS(n) \
+ ((SsxInterval)((__ssx_timebase_frequency_mhz * (SsxInterval)(n)) / 1000))
+#endif
+
+
+// Application and kernel tracing. Tracing can only be enabled if the port
+// defines the trace macros in that case.
+
+/// Enable SSX application tracing
+#ifndef SSX_TRACE_ENABLE
+#define SSX_TRACE_ENABLE 0
+#endif
+
+/// Enable SSX kernel tracing
+#ifndef SSX_KERNEL_TRACE_ENABLE
+#define SSX_KERNEL_TRACE_ENABLE 0
+#endif
+
+#if !SSX_TRACE_ENABLE
+#define SSX_TRACE(event)
+#endif
+
+#if !SSX_KERNEL_TRACE_ENABLE
+
+#define SSX_TRACE_THREAD_SLEEP(priority)
+#define SSX_TRACE_THREAD_WAKEUP(priority)
+#define SSX_TRACE_THREAD_SEMAPHORE_PEND(priority)
+#define SSX_TRACE_THREAD_SEMAPHORE_POST(priority)
+#define SSX_TRACE_THREAD_SEMAPHORE_TIMEOUT(priority)
+#define SSX_TRACE_THREAD_SUSPENDED(priority)
+#define SSX_TRACE_THREAD_DELETED(priority)
+#define SSX_TRACE_THREAD_COMPLETED(priority)
+#define SSX_TRACE_THREAD_MAPPED_RUNNABLE(priority)
+#define SSX_TRACE_THREAD_MAPPED_SEMAPHORE_PEND(priority)
+#define SSX_TRACE_THREAD_MAPPED_SLEEPING(priority)
+
+
+#endif /* SSX_KERNEL_TRACE_ENABLE */
+
+
+#ifndef __ASSEMBLER__
+
+#include <stddef.h>
+#include <stdint.h>
+
+/// The timebase frequency in Hz; A parameter to ssx_initialize()
+extern uint32_t __ssx_timebase_frequency_hz;
+
+/// The timebase frequency in KHz
+extern uint32_t __ssx_timebase_frequency_khz;
+
+/// The timebase frequency in Mhz
+extern uint32_t __ssx_timebase_frequency_mhz;
+
+
+typedef unsigned long int SsxAddress;
+
+typedef uint8_t SsxThreadState;
+
+typedef uint8_t SsxThreadPriority;
+
+typedef uint8_t SsxThreadFlags;
+
+typedef uint32_t SsxSemaphoreCount;
+
+typedef uint64_t SsxTimebase;
+
+typedef SSX_TIME_INTERVAL_TYPE SsxInterval;
+
+#include "ssx_port_types.h"
+
+typedef struct {
+
+ /// A priority queue of threads pending on the semaphore.
+ SsxThreadQueue pending_threads;
+
+ /// The current semaphore count.
+ SsxSemaphoreCount count;
+
+ /// The maximum allowable count - for error checking.
+ SsxSemaphoreCount max_count;
+
+} SsxSemaphore;
+
+
+/// Compile-time initialize an SsxSemaphore structure
+///
+/// This low-level macro creates a structure initializatin of an SsxSemaphore
+/// structure. This can be used for example to create compile-time initialized
+/// arrays of semaphores.
+#define SSX_SEMAPHORE_INITIALIZATION(_initial_count, _max_count) \
+ {.pending_threads = 0, \
+ .count = (_initial_count), \
+ .max_count = (_max_count)}
+
+
+/// Declare and initialize a semaphore
+#define SSX_SEMAPHORE(sem, initial_count, max_count) \
+ SsxSemaphore sem = SSX_SEMAPHORE_INITIALIZATION(initial_count, max_count)
+
+
+/// A generic doubly-linked list object
+///
+/// This object functions both as a sentinel mode for a deque as well as a
+/// pointer container for elements in deques. The SSX API assumes that
+/// queueable structures will be defined with an SsxDeque structure as the
+/// initial 'data member' of the structure. This allows a pointer to a queue
+/// element to be cast to a pointer to an SsxDeque and vice-versa.
+
+typedef struct SsxDeque {
+
+ /// Pointer to the head or the next element in a deque.
+ ///
+ /// When an SsxDeque is used as the sentinel node for a queue, \a next
+ /// points to the head of the queue, and the condition (next == \<self\>)
+ /// indicates an empty SsxDeque. By convention the condition (\a next ==
+ /// 0) is used to indicate that a queue element is not enqueued.
+ struct SsxDeque* next;
+
+ /// Pointer to the tail or previous element in a deque.
+ ///
+ /// When a DQueue is used as the sentinel node for a queue, \a previous
+ /// points to the tail of the queue.
+ struct SsxDeque* previous;
+
+} SsxDeque;
+
+
+typedef void (*SsxTimerCallback)(void *);
+
+#define SSX_TIMER_CALLBACK(callback) void callback(void *)
+
+struct SsxTimer;
+
+/// The SSX timer object
+
+typedef struct SsxTimer {
+
+ /// The time queue management pointers
+ ///
+ /// This pointer container is defined as the first element of the
+ /// structure to allow the SsxTimer to be cast to an SsxDeque and
+ /// vice-versa.
+ SsxDeque deque;
+
+ /// The absolute timeout of the timer.
+ SsxTimebase timeout;
+
+ /// The timer period
+ ///
+ /// If not 0, then this is a periodic timer and it will be automatically
+ /// rescheduled in absolute time from the previous timeout.
+ SsxInterval period;
+
+ /// The timer callback
+ ///
+ /// For SSX thread timers used to implement Sleep and semaphore pend
+ /// timeouts this field is initialized to __ssx_thread_timeout().
+ SsxTimerCallback callback;
+
+ /// Private data passed to the callback.
+ ///
+ /// For SSX thread timers used to implement Sleep and semaphore pend this
+ /// field is initialized to a pointer to the thread.
+ void *arg;
+
+ /// Options for timer processing; See \ref ssx_timer_options
+ uint8_t options;
+
+} SsxTimer;
+
+/// \defgroup ssx_timer_options SSX Timer Options
+/// @{
+
+/// Allow interrupt preemption during the callback
+///
+/// This is the normal mode for SsxTimer objects scheduled by SSX kernal
+/// mechanisms. The timer callbacks effectively run as if inside a
+/// highest-priority thread, allowing other interrupts to preempt them.
+#define SSX_TIMER_CALLBACK_PREEMPTIBLE 0x1
+
+/// @}
+
+
+// Threads
+
+typedef void (*SsxThreadRoutine)(void *arg);
+
+#define SSX_THREAD_ROUTINE(f) void f(void *arg);
+
+typedef struct {
+
+ /// Stack pointer saved during context switches. Assembler code expects
+ /// this to always be at address offset 0 from the thread pointer.
+ SsxAddress saved_stack_pointer;
+
+ /// This is 1 past the last valid byte address of the thread stack.
+ /// Assembler code expects this to always be at address offset (sizeof
+ /// SsxAddress) from the thread pointer.
+ SsxAddress stack_limit;
+
+ /// This is the original base of the stack.
+ /// Assembler code expects this to always be at address offset 2 * (sizeof
+ /// SsxAddress) from the thread pointer.
+ SsxAddress stack_base;
+
+ /// If the thread is blocked on a semaphore, then this is the semaphore the
+ /// thread is blocked on.
+ SsxSemaphore *semaphore;
+
+ /// The thread priority.
+ SsxThreadPriority priority;
+
+ /// The thread state; See \ref ssx_thread_states
+ SsxThreadState state;
+
+ /// Thread flags; See \ref ssx_thread_flags
+ SsxThreadFlags flags;
+
+ /// The timer structure handles Sleep and blocking on a semaphore with
+ /// timeout.
+ SsxTimer timer;
+
+} SsxThread;
+
+
+// Initialization APIs
+
+int
+ssx_initialize(SsxAddress noncritical_stack,
+ size_t noncritical_stack_size,
+ SsxAddress critical_stack,
+ size_t critical_stack_size,
+ SsxTimebase initial_timebase,
+ uint32_t timebase_frequency_hz);
+
+
+// Timebase APIs
+
+SsxTimebase
+ssx_timebase_get(void);
+
+void
+ssx_timebase_set(SsxTimebase timebase);
+
+// Interrupt preemption APIs
+
+int
+ssx_interrupt_preemption_enable(void);
+
+int
+ssx_interrupt_preemption_disable(void);
+
+// Timer APIs
+
+int
+ssx_timer_create(SsxTimer *timer,
+ SsxTimerCallback callback,
+ void *arg);
+
+int
+ssx_timer_create_nonpreemptible(SsxTimer *timer,
+ SsxTimerCallback callback,
+ void *arg);
+
+int
+ssx_timer_schedule_absolute(SsxTimer *timer,
+ SsxTimebase time,
+ SsxInterval period);
+
+int
+ssx_timer_schedule(SsxTimer *timer,
+ SsxInterval interval,
+ SsxInterval period);
+
+int
+ssx_timer_cancel(SsxTimer *timer);
+
+int
+ssx_timer_info_get(SsxTimer *timer,
+ SsxTimebase *timeout,
+ int *active);
+
+// Thread APIs
+
+int
+ssx_thread_create(SsxThread *thread,
+ SsxThreadRoutine thread_routine,
+ void *arg,
+ SsxAddress stack,
+ size_t stack_size,
+ SsxThreadPriority priority);
+
+int
+ssx_start_threads(void);
+
+int
+ssx_thread_resume(SsxThread *thread);
+
+int
+ssx_thread_suspend(SsxThread *thread);
+
+int
+ssx_thread_delete(SsxThread *thread);
+
+int
+ssx_complete(void);
+
+int
+ssx_sleep_absolute(SsxTimebase time);
+
+int
+ssx_sleep(SsxInterval interval);
+
+int
+ssx_thread_info_get(SsxThread *thread,
+ SsxThreadState *state,
+ SsxThreadPriority *priority,
+ int *runnable);
+
+int
+ssx_thread_priority_change(SsxThread *thread,
+ SsxThreadPriority new_priority,
+ SsxThreadPriority *old_priority);
+
+int
+ssx_thread_at_priority(SsxThreadPriority priority,
+ SsxThread **thread);
+
+int
+ssx_thread_priority_swap(SsxThread* thread_a, SsxThread* thread_b);
+
+
+// Semaphore APIs
+
+int
+ssx_semaphore_create(SsxSemaphore *semaphore,
+ SsxSemaphoreCount initial_count,
+ SsxSemaphoreCount max_count);
+
+int
+ssx_semaphore_post(SsxSemaphore *semaphore);
+
+int
+ssx_semaphore_pend(SsxSemaphore *semaphore,
+ SsxInterval timeout);
+
+int
+ssx_semaphore_release_all(SsxSemaphore *semaphore);
+
+
+int
+ssx_semaphore_info_get(SsxSemaphore *semaphore,
+ SsxSemaphoreCount *count,
+ int *pending);
+
+void
+ssx_semaphore_post_handler(void *arg,
+ SsxIrqId irq,
+ int priority);
+
+// Misc. APIs
+
+void
+ssx_halt() __attribute__ ((noreturn));
+
+// Deque APIs
+
+int
+ssx_deque_sentinel_create(SsxDeque *deque);
+
+int
+ssx_deque_element_create(SsxDeque *element);
+
+
+/// Check for an empty SsxDeque
+///
+/// \param deque The sentinel node of a deque
+///
+/// \retval 0 The SsxDeque is not empty
+///
+/// \retval 1 The SsxDeque is empty
+
+static inline int
+ssx_deque_is_empty(SsxDeque *deque)
+{
+ return (deque == deque->next);
+}
+
+
+/// Check if an SsxDeque element is currently enqueued
+///
+/// \param element Typically the SsxDeque object of a queable structure
+///
+/// \retval 0 The element is not currently enqueued
+///
+/// \retval 1 The element is currently enqueued
+
+static inline int
+ssx_deque_is_queued(SsxDeque *element)
+{
+ return (element->next != 0);
+}
+
+
+/// Append an element to the tail of a deque (FIFO order)
+///
+/// \param deque The sentinel node of a deque
+///
+/// \param element Typically the SsxDeque object of a queable structure
+///
+/// It is an error to call this API on an element that is already enqueued,
+/// but the API does not check for this error.
+
+static inline void
+ssx_deque_push_back(SsxDeque *deque, SsxDeque *element)
+{
+ deque->previous->next = element;
+ element->previous = deque->previous;
+ element->next = deque;
+ deque->previous = element;
+}
+
+
+/// Push an element at the head of a deque (LIFO order)
+///
+/// \param deque The sentinel node of a deque
+///
+/// \param element Typically the SsxDeque object of a queable structure
+///
+/// It is an error to call this API on an element that is already enqueued,
+/// but the API does not check for this error.
+
+static inline void
+ssx_deque_push_front(SsxDeque *deque, SsxDeque *element)
+{
+ deque->next->previous = element;
+ element->next = deque->next;
+ element->previous = deque;
+ deque->next = element;
+}
+
+/// Pop an element from the head of a deque
+///
+/// \param deque The sentinel node of a deque
+///
+/// \retval 0 The SsxDeque was empty prior to the call
+///
+/// \retval non-0 A pointer to the previous head of the deque, which has been
+/// removed from the deque and marked as no longer queued.
+
+// The cast of 'head' is used to remove the 'volatile' attribute.
+
+static inline SsxDeque *
+ssx_deque_pop_front(SsxDeque *deque)
+{
+ SsxDeque *head;
+
+ if (ssx_deque_is_empty(deque)) {
+ return 0;
+ } else {
+ head = (SsxDeque *)(deque->next);
+ deque->next = head->next;
+ deque->next->previous = deque;
+ head->next = 0;
+ return head;
+ }
+}
+
+
+/// Remove a deque element from any position in the deque
+///
+/// \param element Typically the SsxDeque object of a queable structure
+///
+/// It is an error to call this API on an element that is not currently
+/// enqueued, but the API does not check for this error.
+
+static inline void
+ssx_deque_delete(SsxDeque *element)
+{
+ element->previous->next = element->next;
+ element->next->previous = element->previous;
+ element->next = 0;
+}
+
+
+/// Cast a pointer to another type, in a way that won't cause warnings
+
+#define SSX_CAST_POINTER(t, p) ((t)((SsxAddress)(p)))
+
+
+/// \page ssx_errors SSX API and Kernel Error Handling
+///
+/// Error checking in the SSX API consumes a significant amount of code space.
+/// Approximately 20% of the object code in the PPC405 port is devoted to
+/// error checking. Presumably a like amount of time overhead is also added to
+/// SSX API calls by this checking.
+///
+/// API error checking can be disabled to save space and time in the kernel.
+/// API errors can also be configured to cause kernel panics, allowing
+/// applications to be coded without the overhead of error checking but still
+/// providing an escape in the event of application errors or (unlikely)
+/// hardware failures. The SSX default is to check for API errors and kernel
+/// invariants, and panic should errors occur.
+///
+/// SSX follows the Unix convention that a successful call of an API returns 0
+/// (SSX_OK), but returns a negative code in the event of failure, or to
+/// provide further information. The error codes are all defined as manifest
+/// constants.
+///
+/// Some negative codes returned by SSX APIs are not considered errors. These
+/// conditions are always checked, never cause a panic if they occur, and
+/// their interpretation is always left to the application. See the detailed
+/// documentation for each API for lists of error and non-error codes returned
+/// by the API.
+///
+/// There are three configuration options that control error handling in the
+/// SSX API and kernel:
+///
+/// \c SSX_ERROR_CHECK_API
+///
+/// \arg \b 0 - No SSX API error checking. APIs that potentially return error
+/// codes will always return 0 (SSX_OK) instead of an error code. Those
+/// APIs that return negative codes that are not errors (see Table 1.5)
+/// always return the negative non-error codes when appropriate.
+///
+/// \arg \b 1 - (Default) All SSX API errors are checked. The behavior in
+/// the event of an error is defined by the configuration option
+/// SSX_ERROR_PANIC.
+///
+/// \c SSX_ERROR_CHECK_KERNEL
+///
+/// \arg \b 0 - No kernel invariant error checking is done.
+///
+/// \arg \b 1 - (Default) Selected kernel invariants are checked. The overhead
+/// for these checks should be minimal.
+///
+/// \c SSX_ERROR_PANIC
+///
+/// \arg \b 0 - SSX API calls return negative error codes in the event of
+/// errors. Note that SSX kernel invariants always cause a panic if
+/// violations occur.
+///
+/// \arg \b 1 - (Default) In the event of errors SSX APIs invoke SSX_PANIC(code),
+/// where code is a positive error code. Kernel invariant checks always
+/// cause a panic if violations are detected.
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* __SSX_API_H__ */
diff --git a/src/ssx/ssx/ssx_core.c b/src/ssx/ssx/ssx_core.c
new file mode 100755
index 0000000..7fa484a
--- /dev/null
+++ b/src/ssx/ssx/ssx_core.c
@@ -0,0 +1,81 @@
+// $Id: ssx_core.c,v 1.2 2014/02/03 01:30:44 daviddu Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ssx/ssx/ssx_core.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ssx_core.c
+/// \brief Core routines for the SSX kernel.
+///
+/// The entry points in this file are routines that are expected to be needed
+/// at runtime by all SSX applications. This file also serves as a place for
+/// kernel global variables to be realized.
+
+#define __SSX_CORE_C__
+
+#include "ssx.h"
+
+#if !SSX_TIMER_SUPPORT
+
+/// If there is no timer support, then any call of the timer interrupt handler
+/// is considered a fatal error.
+
+void
+__ssx_timer_handler()
+{
+ SSX_PANIC(SSX_NO_TIMER_SUPPORT);
+}
+
+#endif /* SSX_TIMER_SUPPORT */
+
+
+/// Initialize an SsxDeque sentinel node
+///
+/// \param deque The sentinel node of the deque
+///
+/// SSX has no way of knowing whether the \a deque is currently in use, so
+/// this API must only be called on unitialized or otherwise unused sentinel
+/// nodes.
+///
+/// \retval 0 success
+///
+/// \retval -SSX_INVALID_DEQUE_SENTINEL The \a deque pointer was null
+
+int
+ssx_deque_sentinel_create(SsxDeque *deque)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(deque == 0, SSX_INVALID_DEQUE_SENTINEL);
+ }
+
+ deque->next = deque->previous = deque;
+ return 0;
+}
+
+
+/// Initialize an SsxDeque element
+///
+/// \param element Typically the SsxDeque object of a queable structure
+///
+/// SSX has no way of knowing whether the \a element is currently in use, so
+/// this API must only be called on unitialized or otherwise unused deque
+/// elements.
+///
+/// \retval 0 success
+///
+/// \retval -SSX_INVALID_DEQUE_ELEMENT The \a element pointer was null
+
+int
+ssx_deque_element_create(SsxDeque *element)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(element == 0, SSX_INVALID_DEQUE_ELEMENT);
+ }
+
+ element->next = 0;
+ return 0;
+}
+
+#undef __SSX_CORE_C__
diff --git a/src/ssx/ssx/ssx_init.c b/src/ssx/ssx/ssx_init.c
new file mode 100755
index 0000000..fc12a9b
--- /dev/null
+++ b/src/ssx/ssx/ssx_init.c
@@ -0,0 +1,159 @@
+// $Id: ssx_init.c,v 1.2 2014/02/03 01:30:44 daviddu Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ssx/ssx/ssx_init.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ssx_init.c
+/// \brief SSX initialization
+///
+/// The entry points in this file are initialization routines - they are never
+/// needed after SSX initialization and their code space could be reclaimed by
+/// the application after initialization if required.
+
+#include "ssx.h"
+
+uint32_t __ssx_timebase_frequency_hz;
+uint32_t __ssx_timebase_frequency_khz;
+uint32_t __ssx_timebase_frequency_mhz;
+
+
+/// Initialize SSX.
+///
+/// \param noncritical_stack A stack area for noncritical interrupt handlers.
+///
+/// \param noncritical_stack_size The size (in bytes) of the stack area for
+/// noncritical interrupt handlers.
+///
+/// \param critical_stack A stack area for critical interrupt handlers.
+///
+/// \param critical_stack_size The size (in bytes) of the stack area for
+/// critical interrupt handlers.
+///
+/// \param initial_timebase The initial value of the SSX timebase. If this
+/// argument is given as the special value \c SSX_TIMEBASE_CONTINUE, then the
+/// timebase is not reset.
+///
+/// \param timebase_frequency_hz The frequency of the SSX timebase in Hz.
+///
+/// This routine \e must be called before any other SSX / routines, and \e
+/// should be called before any interrupts are enabled.
+///
+/// Return values other than SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SSX_INVALID_ARGUMENT_INIT A stack pointer is 0 or is given
+/// a 0 size.
+///
+/// \retval -SSX_STACK_OVERFLOW One or both stacks are not large enough to
+/// support a minimum context save in the event of an interrupt.
+
+// Note that SSX does not rely on any static initialization of dynamic
+// variables. In debugging sessions using RAM-resident SSX images it is
+// assumed that the processor may be reset at any time, so we always need to
+// reset everything at initialization.
+
+int
+ssx_initialize(SsxAddress noncritical_stack,
+ size_t noncritical_stack_size,
+ SsxAddress critical_stack,
+ size_t critical_stack_size,
+ SsxTimebase initial_timebase,
+ uint32_t timebase_frequency_hz)
+{
+ int rc;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF((noncritical_stack == 0) ||
+ (noncritical_stack_size == 0) ||
+ (critical_stack == 0) ||
+ (critical_stack_size == 0),
+ SSX_INVALID_ARGUMENT_INIT);
+ }
+
+ if (initial_timebase != SSX_TIMEBASE_CONTINUES) {
+ __ssx_timebase_set(initial_timebase);
+ }
+
+ __ssx_timebase_frequency_hz = timebase_frequency_hz;
+ __ssx_timebase_frequency_khz = timebase_frequency_hz / 1000;
+ __ssx_timebase_frequency_mhz = timebase_frequency_hz / 1000000;
+
+ __ssx_thread_machine_context_default = SSX_THREAD_MACHINE_CONTEXT_DEFAULT;
+
+ rc = __ssx_stack_init(&noncritical_stack, &noncritical_stack_size);
+ if (rc) {
+ return rc;
+ }
+
+ __ssx_noncritical_stack = noncritical_stack;
+ __ssx_noncritical_stack_size = noncritical_stack_size;
+
+ rc = __ssx_stack_init(&critical_stack, &critical_stack_size);
+ if (rc) {
+ return rc;
+ }
+
+ __ssx_critical_stack = critical_stack;
+ __ssx_critical_stack_size = critical_stack_size;
+
+#if SSX_TIMER_SUPPORT
+
+ // Initialize the time queue sentinel as a circular queue, set the next
+ // timeout and clear the cursor.
+
+ ssx_deque_sentinel_create((SsxDeque*)&__ssx_time_queue);
+ __ssx_time_queue.cursor = 0;
+ __ssx_time_queue.next_timeout = SSX_TIMEBASE_MAX;
+
+#endif /* SSX_TIMER_SUPPORT */
+
+#if SSX_THREAD_SUPPORT
+
+ // Clear the priority map. The final entry [SSX_THREADS] is for the idle
+ // thread.
+
+ int i;
+ for (i = 0; i <= SSX_THREADS; i++) {
+ __ssx_priority_map[i] = 0;
+ }
+
+ // Initialize the thread scheduler
+
+ __ssx_thread_queue_clear(&__ssx_run_queue);
+ __ssx_current_thread = 0;
+ __ssx_next_thread = 0;
+ __ssx_delayed_switch = 0;
+
+#endif /* SSX_THREAD_SUPPORT */
+
+ return SSX_OK;
+}
+
+
+/// Call the application main()
+///
+/// __ssx_main() is called from the bootloader. It's only purpose is to
+/// provide a place for the SSX_MAIN_HOOK to be called before main() is
+/// called.
+
+void
+__ssx_main(int argc, char **argv)
+{
+ SSX_MAIN_HOOK;
+
+ int main(int argc, char **argv);
+ main(argc, argv);
+}
+
+
+
+
+
+
+
+
+
diff --git a/src/ssx/ssx/ssx_kernel.h b/src/ssx/ssx/ssx_kernel.h
new file mode 100755
index 0000000..c6a70ca
--- /dev/null
+++ b/src/ssx/ssx/ssx_kernel.h
@@ -0,0 +1,281 @@
+#ifndef __SSX_KERNEL_H__
+#define __SSX_KERNEL_H__
+
+// $Id: ssx_kernel.h,v 1.1.1.1 2013/12/11 21:03:27 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ssx/ssx/ssx_kernel.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ssx_kernel.h
+/// \brief SSX portable kernel (non-API) data and data structures
+///
+/// \todo In theory, as long as the critical section entry/exit macros use GCC
+/// memory barriers, we should be able to eliminate all of the 'volatile'
+/// declarations in SSX code. These have been added to the PPC405 port, so
+/// we should try it.
+
+#ifdef __SSX_CORE_C__
+#define IF__SSX_CORE_C__(x) x
+#define UNLESS__SSX_CORE_C__(x)
+#else
+#define IF__SSX_CORE_C__(x)
+#define UNLESS__SSX_CORE_C__(x) x
+#endif
+
+#if SSX_MINIMIZE_KERNEL_CODE_SPACE
+#define IF_SSX_MINIMIZE_KERNEL_CODE_SPACE(x) x
+#define UNLESS_SSX_MINIMIZE_KERNEL_CODE_SPACE(x)
+#else
+#define IF_SSX_MINIMIZE_KERNEL_CODE_SPACE(x)
+#define UNLESS_SSX_MINIMIZE_KERNEL_CODE_SPACE(x) x
+#endif
+
+
+#ifndef __ASSEMBLER__
+
+/// This is the stack pointer saved when switching from a thread or
+/// non-critical interrupt context to a full-mode critical interrupt context.
+
+UNLESS__SSX_CORE_C__(extern)
+volatile
+SsxAddress __ssx_saved_sp_critical;
+
+/// The critical interrupt stack; constant once defined by the call of
+/// ssx_initialize().
+
+UNLESS__SSX_CORE_C__(extern)
+volatile
+SsxAddress __ssx_critical_stack;
+
+/// This is the stack pointer saved when switching from a thread context to a
+/// full-mode non-critical interrupt context.
+
+UNLESS__SSX_CORE_C__(extern)
+volatile
+SsxAddress __ssx_saved_sp_noncritical;
+
+/// The non-critical interrupt stack; constant once defined by the call of
+/// ssx_initialize().
+
+UNLESS__SSX_CORE_C__(extern)
+volatile
+SsxAddress __ssx_noncritical_stack;
+
+/// This is the run queue - the queue of mapped runnable tasks.
+UNLESS__SSX_CORE_C__(extern)
+volatile
+SsxThreadQueue __ssx_run_queue;
+
+/// This flag is set by \c __ssx_schedule() if a new highest-priority thread
+/// becomes runnable during an interrupt handler. The context switch will
+/// take place at the end of non-critical interrupt processing, and the
+/// interrupt handling code will clear the flag.
+
+UNLESS__SSX_CORE_C__(extern)
+volatile
+int __ssx_delayed_switch;
+
+/// The currently running thread, or NULL (0) to indicate the idle thread
+///
+/// \a __ssx_current_thread holds a pointer to the currently executing
+/// thread. This pointer will be NULL (0) under the following conditions:
+///
+/// - After ssx_initialize() but prior to ssx_start_threads()
+///
+/// - After ssx_start_threads(), when no threads are runnable. In this case
+/// the NULL (0) value indicates that the SSX idle thread is 'running'.
+///
+/// - After ssx_start_threads(), when the current (non-idle) thread has
+/// completed or been deleted.
+///
+/// If \a __ssx_current_thread == 0 then there is no requirement to save any
+/// register state on a context switch, either because the SSX idle thread has
+/// no permanent context, or because any thread context on the kernel stack is
+/// associated with a deleted thread.
+///
+/// If \a __ssx_current_thread != 0 then \a __ssx_current_thread is a pointer
+/// to the currently executing thread. In an interrupt handler \a
+/// ssx_current_thread is a pointer to the thread whose context is saved on
+/// the kernel stack.
+UNLESS__SSX_CORE_C__(extern)
+volatile
+SsxThread* __ssx_current_thread;
+
+/// The thread to switch to during the next context switch, or NULL (0).
+///
+/// \a __ssx_next_thread is computed by __ssx_schedule(). \a
+/// __ssx_next_thread holds a pointer to the thread to switch to at the next
+/// context switch. In a thread context the switch happens immediately if \a
+/// __ssx_next_thread == 0 or \a __ssx_next_thread != \a __ssx_current_thread.
+/// In an interrupt context the check happens at the end of processing all
+/// SSX_NONCRITICAL interrupts.
+///
+/// \a __ssx_next_thread may be NULL (0) under the following
+/// conditions:
+///
+/// - After ssx_initialize() but prior to ssx_start_threads(), assuming no
+/// threads have been made runnable.
+///
+/// - After ssx_start_threads(), when no threads are runnable. In this case
+/// the NULL (0) value indicates that the SSX idle thread is the next thread
+/// to 'run'.
+///
+/// If \a __ssx_next_thread == 0 then there is no requirement to restore
+/// any register state on a context switch, because the SSX idle thread has
+/// no permanent context.
+///
+/// If \a __ssx_next_thread != 0 then \a __ssx_next_thread is a pointer
+/// to the thread whose context will be restored at the next context switch.
+UNLESS__SSX_CORE_C__(extern)
+volatile
+SsxThread* __ssx_next_thread;
+
+/// The priority of \a __ssx_next_thread
+///
+/// If \a __ssx_next_thread == 0, the \a __ssx_next_priority == SSX_THREADS.
+UNLESS__SSX_CORE_C__(extern)
+volatile
+SsxThreadPriority __ssx_next_priority;
+
+/// This variable holds the default thread machine context for newly created
+/// threads. The idle thread also uses this context. This variable is normally
+/// constant after the call of \c ssx_initialize().
+
+UNLESS__SSX_CORE_C__(extern)
+volatile
+SsxMachineContext __ssx_thread_machine_context_default;
+
+
+/// The size of the noncritical stack (bytes).
+
+UNLESS__SSX_CORE_C__(extern)
+volatile
+size_t __ssx_noncritical_stack_size;
+
+/// The size of the critical stack (bytes).
+
+UNLESS__SSX_CORE_C__(extern)
+volatile
+size_t __ssx_critical_stack_size;
+
+/// This table maps priorities to threads, and contains SSX_THREADS + 1
+/// entries. The final entry is for the idle thread and will always be null
+/// after initizlization.
+
+UNLESS__SSX_CORE_C__(extern)
+volatile
+SsxThread* __ssx_priority_map[SSX_THREADS + 1];
+
+/// The SSX time queue structure
+///
+/// This structure is defined for use by the kernel, however applications
+/// could also use this structure to define their own time queues.
+
+typedef struct {
+
+ /// A sentinel node for the time queue.
+ ///
+ /// The time queue is an SsxDeque managed as a FIFO queue for queue
+ /// management purpose, although events time out in time order.
+ ///
+ /// This pointer container is defined as the first element of the
+ /// structure to allow the SsxTimeQueue to be cast to an SsxDeque.
+ SsxDeque queue;
+
+ /// The next timeout in absolute time.
+ SsxTimebase next_timeout;
+
+ /// A pointer to allow preemption of time queue processing
+ ///
+ /// If non-0, then this is the next timer in the time queue to handle, or
+ /// a pointer to the \a queue object indicating no more timers to handle.
+ ///
+ /// \a cursor != 0 implies that time queue handler is in the midst of
+ /// processing the time queue, but has enabled interrupt preemption for
+ /// processing a timer handler. This means that 1) if the timer pointed to
+ /// by \a cursor is deleted then the cursor must be assigned to the
+ /// next timer in the queue; and 2) if a new timer is scheduled then
+ /// activating the next timeout will be handled by the timer handler.
+ SsxDeque* cursor;
+
+} SsxTimeQueue;
+
+UNLESS__SSX_CORE_C__(extern)
+SsxTimeQueue __ssx_time_queue;
+
+/// Return a pointer to the SsxThread object of the currently running thread,
+/// or NULL (0) if SSX is idle or has not been started.
+///
+/// In this API the current thread is not volatile - it will never change
+/// inside application code - thus the 'volatile' is cast away. The SSX kernel
+/// does not (must not) use this API.
+
+UNLESS__SSX_CORE_C__(extern)
+inline SsxThread *
+ssx_current(void)
+{
+ return (SsxThread *)__ssx_current_thread;
+}
+
+
+/// Set the timebase. This is only called at initialization. Machine
+/// specific.
+
+void
+__ssx_timebase_set(SsxTimebase t);
+
+/// Schedule the next timeout in a machine-specific way.
+
+void
+__ssx_schedule_hardware_timeout(SsxTimebase timeout);
+
+/// Cancel the next timeout in a machine-specific way.
+
+void
+__ssx_cancel_hardware_timeout(void);
+
+/// The thread timeout handler. Portable.
+
+SSX_TIMER_CALLBACK(__ssx_thread_timeout);
+
+/// Generic stack initialization. Portable.
+
+int
+__ssx_stack_init(SsxAddress *stack,
+ size_t *size);
+
+/// Machine-specific thread context initialization.
+
+void
+__ssx_thread_context_initialize(SsxThread *thread,
+ SsxThreadRoutine thread_routine,
+ void *arg);
+
+/// Machine specific resumption of __ssx_next_thread at __ssx_next_priority
+/// without saving the current context.
+void
+__ssx_next_thread_resume(void);
+
+/// Schedule a timer in the time queue. Portable.
+void
+__ssx_timer_schedule(SsxTimer *timer);
+
+/// Remove a timer from the time queue. Portable.
+int
+__ssx_timer_cancel(SsxTimer *timer);
+
+void
+__ssx_schedule(void);
+
+
+// Call the application main(). Portable.
+
+void
+__ssx_main(int argc, char **argv);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* __SSX_KERNEL_H__ */
diff --git a/src/ssx/ssx/ssx_macros.h b/src/ssx/ssx/ssx_macros.h
new file mode 100755
index 0000000..76d3ba7
--- /dev/null
+++ b/src/ssx/ssx/ssx_macros.h
@@ -0,0 +1,119 @@
+#ifndef __SSX_MACROS_H__
+#define __SSX_MACROS_H__
+
+// $Id: ssx_macros.h,v 1.2 2014/02/03 01:30:44 daviddu Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ssx/ssx/ssx_macros.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ssx_macros.h
+/// \brief Boilerplate macros for SSX
+
+/// This macro encapsulates error handling boilerplate for code that uses the
+/// SSX API-type error handling, for errors that do not occur in critical
+/// sections.
+
+#define SSX_ERROR(code) \
+ do { \
+ if (SSX_ERROR_PANIC) { \
+ SSX_PANIC(code); \
+ } else { \
+ return -(code); \
+ } \
+ } while (0)
+
+
+/// This macro encapsulates error handling boilerplate in the SSX API
+/// functions, for errors that do not occur in critical sections.
+
+#define SSX_ERROR_IF(condition, code) \
+ do { \
+ if (condition) { \
+ SSX_ERROR(code); \
+ } \
+ } while (0)
+
+
+/// This macro encapsulates error handling boilerplate in the SSX API
+/// functions, for errors that do not occur in critical sections and always
+/// force a kernel panic, indicating a kernel or API bug.
+
+#define SSX_PANIC_IF(condition, code) \
+ do { \
+ if (condition) { \
+ SSX_PANIC(code); \
+ } \
+ } while (0)
+
+
+/// This macro encapsulates error handling boilerplate in the SSX API
+/// functions, for errors that do not occur in critical sections.
+/// The error handling will only be enabled when SSX_ERROR_CHECK_API
+/// is enabled.
+
+#define SSX_ERROR_IF_CHECK_API(condition, code) \
+ do { \
+ if (SSX_ERROR_CHECK_API) { \
+ SSX_ERROR_IF(condition, code); \
+ } \
+ } while (0)
+
+/// This macro encapsulates error handling boilerplate in the SSX API
+/// functions, for errors that occur in critical sections.
+
+#define SSX_ERROR_IF_CRITICAL(condition, code, context) \
+ do { \
+ if (condition) { \
+ if (SSX_ERROR_PANIC) { \
+ SSX_PANIC(code); \
+ ssx_critical_section_exit(context); \
+ } else { \
+ ssx_critical_section_exit(context); \
+ return -(code); \
+ } \
+ } \
+ } while (0)
+
+
+/// This is a general macro for errors that require cleanup before returning
+/// the error code.
+
+#define SSX_ERROR_IF_CLEANUP(condition, code, cleanup) \
+ do { \
+ if (condition) { \
+ if (SSX_ERROR_PANIC) { \
+ SSX_PANIC(code); \
+ cleanup; \
+ } else { \
+ cleanup; \
+ return -(code); \
+ } \
+ } \
+ } while (0)
+
+
+/// Most SSX APIs can not be called from critical interrupt contexts.
+
+#define SSX_ERROR_IF_CRITICAL_INTERRUPT_CONTEXT() \
+ SSX_ERROR_IF(__ssx_kernel_context_critical_interrupt(), \
+ SSX_ILLEGAL_CONTEXT_CRITICAL_INTERRUPT)
+
+
+/// Some SSX APIs can only be called from thread contexts - these are APIs
+/// that threads call on 'themselves'.
+
+#define SSX_ERROR_UNLESS_THREAD_CONTEXT() \
+ SSX_ERROR_IF(!__ssx_kernel_context_thread(), \
+ SSX_ILLEGAL_CONTEXT_THREAD_CONTEXT)
+
+
+/// Some SSX APIs must be called from an interrupt context only.
+
+#define SSX_ERROR_UNLESS_ANY_INTERRUPT_CONTEXT() \
+ SSX_ERROR_IF(!__ssx_kernel_context_any_interrupt(), \
+ SSX_ILLEGAL_CONTEXT_INTERRUPT_CONTEXT)
+
+#endif /* __SSX_MACROS_H__ */
diff --git a/src/ssx/ssx/ssx_semaphore_core.c b/src/ssx/ssx/ssx_semaphore_core.c
new file mode 100755
index 0000000..f1f64e8
--- /dev/null
+++ b/src/ssx/ssx/ssx_semaphore_core.c
@@ -0,0 +1,331 @@
+// $Id: ssx_semaphore_core.c,v 1.2 2014/02/03 01:30:44 daviddu Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ssx/ssx/ssx_semaphore_core.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ssx_semaphore_core.c
+/// \brief SSX semaphore APIs
+///
+/// The entry points in this file are considered 'core' routines that will
+/// always be present at runtime in any SSX application that enables
+/// semaphores.
+
+#include "ssx.h"
+
+/// Post a count to a semaphore
+///
+/// \param semaphore A pointer to the semaphore
+///
+/// If any thread is pending on the semaphore, the highest priority thread
+/// will be made runnable and the internal count will remain 0.
+///
+/// If no thread is pending on the semaphore then the internal count will be
+/// incremented by 1, with overflow wrapping the internal count through 0. If
+/// the \a max_count argument supplied when the semaphore was created is
+/// non-zero and the new internal count is greater than the \a max_count, an
+/// overflow error will be signalled.
+///
+/// Return values other than SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SSX_ILLEGAL_CONTEXT The API was called from a critical interrupt
+/// context.
+///
+/// \retval -SSX_INVALID_SEMAPHORE_AT_POST The \a semaphore is a null (0) pointer.
+///
+/// \retval -SSX_SEMAPHORE_OVERFLOW The \a max_count argument supplied when
+/// the semaphore was created is non-zero and the new internal count is
+/// greater than the \a max_count.
+
+int
+ssx_semaphore_post(SsxSemaphore *semaphore)
+{
+ SsxMachineContext ctx;
+ SsxThreadPriority priority;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF_CRITICAL_INTERRUPT_CONTEXT();
+ SSX_ERROR_IF(semaphore == 0, SSX_INVALID_SEMAPHORE_AT_POST);
+ }
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ priority = __ssx_thread_queue_min(&(semaphore->pending_threads));
+
+ if (priority != SSX_IDLE_THREAD_PRIORITY) {
+
+ __ssx_thread_queue_delete(&(semaphore->pending_threads), priority);
+ __ssx_thread_queue_insert(&__ssx_run_queue, priority);
+
+ SSX_TRACE_THREAD_SEMAPHORE_POST(priority);
+
+ __ssx_schedule();
+
+ } else {
+
+ semaphore->count++;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF((semaphore->max_count > 0) &&
+ (semaphore->count > semaphore->max_count),
+ SSX_SEMAPHORE_OVERFLOW);
+ }
+ }
+
+ ssx_critical_section_exit(&ctx);
+
+ return SSX_OK;
+}
+
+
+/// Pend on a semaphore with timeout
+///
+/// \param semaphore A pointer to the semaphore
+///
+/// \param timeout A relative timeout in SSX timebase ticks, including the
+/// special values SSX_NO_WAIT and SSX_WAIT_FOREVER
+///
+/// This API is normally called from threads, and can only be successfully
+/// called from interupt handlers under special conditions.
+///
+/// If the internal count of the \a semaphore is non-zero, the internal count
+/// is decremented by one and execution of the caller continues.
+///
+/// If the internal count of the \a semaphore is zero and the \a timeout is
+/// SSX_NO_WAIT (0) then the call returns immediately with the informational
+/// code -SSX_SEMAPHORE_PEND_NO_WAIT.
+///
+/// If the internal count of the \a semaphore is zero and the \a timeout is
+/// non-zero then a thread will block until either a semaphore count is
+/// acquired or the relative timeout expires. If this condition occurs in a
+/// call from an interrupt context or before threads have been started then
+/// the call will fail with the error \c -SSX_SEMAPHORE_PEND_WOULD_BLOCK.
+///
+/// Once timed out the thread is removed from the semaphore pending queue and
+/// made runnable, and the ssx_semaphore_pend() operation will fail, even if
+/// the semaphore count becomes available before the thread runs again. The
+/// ssx_semaphore_pend() API returns the informational code
+/// -SSX_SEMAPHORE_PEND_TIMED_OUT in this case.
+///
+/// By convention, a timeout interval equal to the maximum possible value of
+/// the \c SsxInterval type is taken to mean "wait forever". A thread blocked
+/// on a semaphore in this mode will never time out. SSX provides this
+/// constant as \c SSX_WAIT_FOREVER.
+///
+/// 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_SEMAPHORE_PEND_NO_WAIT timeout is set to SSX_NO_WAIT
+///
+/// \retval -SSX_SEMAPHORE_PEND_TIMED_OUT The semaphore was not acquired
+/// before the timeout expired.
+///
+/// The following return codes are error codes:
+///
+/// \retval -SSX_ILLEGAL_CONTEXT The API was called from a critical interrupt
+/// context.
+///
+/// \retval -SSX_INVALID_SEMAPHORE_AT_PEND The \a semaphore is a null (0)
+/// pointer.
+///
+/// \retval -SSX_SEMAPHORE_PEND_WOULD_BLOCK The call was made from an
+/// interrupt context (or before threads have been started), the semaphore
+/// internal count was 0 and a non-zero timeout was specified.
+
+// Note: Casting __ssx_current_thread removes the 'volatile' attribute.
+
+int
+ssx_semaphore_pend(SsxSemaphore *semaphore,
+ SsxInterval timeout)
+{
+ SsxMachineContext ctx;
+ SsxThreadPriority priority;
+ SsxThread *thread;
+ SsxTimer *timer = 0;
+ int rc = SSX_OK;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF_CRITICAL_INTERRUPT_CONTEXT();
+ SSX_ERROR_IF(semaphore == 0, SSX_INVALID_SEMAPHORE_AT_PEND);
+ }
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ if (semaphore->count != 0) {
+
+ semaphore->count--;
+
+ } else if (timeout == SSX_NO_WAIT) {
+
+ rc = -SSX_SEMAPHORE_PEND_NO_WAIT;
+
+ } else {
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF_CRITICAL(!__ssx_kernel_context_thread(),
+ SSX_SEMAPHORE_PEND_WOULD_BLOCK,
+ &ctx);
+ }
+
+ thread = (SsxThread *)__ssx_current_thread;
+ priority = thread->priority;
+
+ __ssx_thread_queue_insert(&(semaphore->pending_threads), priority);
+
+ thread->semaphore = semaphore;
+ thread->flags |= SSX_THREAD_FLAG_SEMAPHORE_PEND;
+
+ SSX_TRACE_THREAD_SEMAPHORE_PEND(priority);
+
+ if (timeout != SSX_WAIT_FOREVER) {
+ timer = &(thread->timer);
+ timer->timeout = ssx_timebase_get() + timeout;
+ __ssx_timer_schedule(timer);
+ thread->flags |= SSX_THREAD_FLAG_TIMER_PEND;
+ }
+
+ __ssx_thread_queue_delete(&__ssx_run_queue, priority);
+ __ssx_schedule();
+
+ thread->flags &= ~SSX_THREAD_FLAG_SEMAPHORE_PEND;
+
+ if (thread->flags & SSX_THREAD_FLAG_TIMER_PEND) {
+ if (thread->flags & SSX_THREAD_FLAG_TIMED_OUT) {
+ rc = -SSX_SEMAPHORE_PEND_TIMED_OUT;
+ } else {
+ __ssx_timer_cancel(timer);
+ }
+ thread->flags &=
+ ~(SSX_THREAD_FLAG_TIMER_PEND | SSX_THREAD_FLAG_TIMED_OUT);
+ }
+ }
+
+ ssx_critical_section_exit(&ctx);
+
+ return rc;
+}
+
+
+/// Release all threads blocked on a semaphore
+///
+/// \param semaphore A pointer to a semaphore
+///
+/// This API is provided to allow an SSX semaphore to be used as a thread
+/// barrier. ssx_semaphore_release_all() simultaneously unblocks all threads
+/// (if any) currently pending on a semaphore. A semaphore to be used as a
+/// thread barrier will typically be initialized with
+/// ssx_semaphore_create(\a sem, 0, 0), and sxx_semaphore_post() would never be
+/// called on the \a sem.
+///
+/// This API never modifies the \a count field of the semaphore; If any
+/// threads are blocked on a semaphore the semaphore count is 0 by definition.
+///
+/// Return values other than SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SSX_ILLEGAL_CONTEXT The API was called from a critical interrupt
+/// context.
+///
+/// \retval -SSX_INVALID_SEMAPHORE_AT_RELEASE The \a semaphore is a null (0)
+/// pointer.
+
+int
+ssx_semaphore_release_all(SsxSemaphore* semaphore)
+{
+ SsxMachineContext ctx;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF_CRITICAL_INTERRUPT_CONTEXT();
+ SSX_ERROR_IF(semaphore == 0, SSX_INVALID_SEMAPHORE_AT_RELEASE);
+ }
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ __ssx_thread_queue_union(&__ssx_run_queue, &(semaphore->pending_threads));
+ __ssx_thread_queue_clear(&(semaphore->pending_threads));
+ __ssx_schedule();
+
+ ssx_critical_section_exit(&ctx);
+
+ return SSX_OK;
+}
+
+
+/// Get information about a semaphore.
+///
+/// \param semaphore A pointer to the SsxSemaphore to query
+///
+/// \param count The value returned through this pointer is the current count
+/// of the semaphore. The caller can set this parameter to the null pointer
+/// (0) if this information is not required.
+///
+/// \param pending The value returned through this pointer is the current
+/// number of threads pending on the semaphore. The caller can set this
+/// parameter to the null pointer (0) if this information is not required.
+///
+/// The information returned by this API can only be guaranteed consistent if
+/// the API is called from an SSX_NONCRITICAL critical section. Since the
+/// implementation of this API does not require a critical section, it is not
+/// an error to call this API from a critical interrupt context.
+///
+/// Return values other than SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SSX_INVALID_SEMAPHORE_AT_INFO The \a semaphore is a null (0)
+/// pointer.
+
+int
+ssx_semaphore_info_get(SsxSemaphore* semaphore,
+ SsxSemaphoreCount* count,
+ int* pending)
+
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(semaphore == 0, SSX_INVALID_SEMAPHORE_AT_INFO);
+ }
+
+ if (count) {
+ *count = semaphore->count;
+ }
+ if (pending) {
+ *pending = __ssx_thread_queue_count(&(semaphore->pending_threads));
+ }
+
+ return SSX_OK;
+}
+
+
+/// An simple interrupt handler that posts to a semaphore.
+///
+/// To implement basic event-driven blocking of a thread, install
+/// ssx_semaphore_post_handler() as the handler for a non-critical interrupt
+/// and provide a pointer to the semaphore as the \a arg argument in
+/// ssx_irq_handler_set(). The semaphore should be initialized with
+/// ssx_semaphore_create(&sem, 0, 1). This handler simply disables (masks)
+/// the interrupt, clears the status and calls ssx_semaphore_post() on the
+/// semaphore.
+///
+/// Note that clearing the status in the interrupt controller as done here is
+/// effectively a no-op for level-sensitive interrupts. In the level-sensitive
+/// case any thread pending on the semaphore must reset the interrupt
+/// condition in the device before re-enabling the interrupt.
+
+void
+ssx_semaphore_post_handler_full(void *arg, SsxIrqId irq, int priority)
+{
+ ssx_irq_disable(irq);
+ ssx_irq_status_clear(irq);
+ ssx_semaphore_post((SsxSemaphore *)arg);
+}
+
+SSX_IRQ_FAST2FULL(ssx_semaphore_post_handler, ssx_semaphore_post_handler_full);
diff --git a/src/ssx/ssx/ssx_semaphore_init.c b/src/ssx/ssx/ssx_semaphore_init.c
new file mode 100755
index 0000000..98bba89
--- /dev/null
+++ b/src/ssx/ssx/ssx_semaphore_init.c
@@ -0,0 +1,84 @@
+// $Id: ssx_semaphore_init.c,v 1.2 2014/02/03 01:30:44 daviddu Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ssx/ssx/ssx_semaphore_init.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ssx_semaphore_init.c
+/// \brief SSX semaphore API initialization routines
+///
+/// The entry points in this file are routines that are typically used during
+/// initialization, and their code space could be deallocated and recovered if
+/// no longer needed by the application after initialization.
+
+#include "ssx.h"
+
+/// Create (initialize) a semaphore
+///
+/// \param semaphore A pointer to an SsxSemaphore structure to initialize
+///
+/// \param initial_count The initial count of the semaphore
+///
+/// \param max_count The maximum count allowed in the semaphore, for error
+/// checking
+///
+/// Semaphores are created (initialized) by a call of \c
+/// ssx_semaphore_create(), using an application-provided instance of an \c
+/// SsxSemaphore structure. This structure \e is the semaphore, so the
+/// application must never modify the structure if the semaphore is in use.
+/// SSX has no way to know if an \c SsxSemaphore structure provided to
+/// \c ssx_semaphore_create() is safe to use as a semaphore, and will silently
+/// modify whatever memory is provided.
+///
+/// SSX provides two simple overflow semantics based on the value of max_count
+/// in the call of \c ssx_semaphore_create().
+///
+/// If \a max_count = 0, then posting to the semaphore first increments the
+/// internal count by 1. Overflows are ignored and will wrap the internal
+/// count through 0.
+///
+/// If \a max_count != 0, then posting to the semaphore first increments the
+/// internal count by 1, wrapping through 0 in the event of overflow. If the
+/// resulting count is greater than max_count, \c ssx_semaphore_post() will
+/// return the error \c -SSX_SEMAPHORE_POST_OVERFLOW to the caller.
+///
+/// In most applications it is probably best to use the \a max_count != 0
+/// semantics to trap programming errors, unless there is a specific
+/// application where overflow is expected and ignorable. As a fine point of
+/// the specification, a \a max_count of 0 is equivalent to a max_count of
+/// 0xFFFFFFFF.
+///
+/// Return values other then SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SSX_INVALID_SEMAPHORE_AT_CREATE The \a semaphore is a null (0)
+/// pointer.
+///
+/// \retval -SSX_INVALID_ARGUMENT_SEMAPHORE The \a max_count is non-zero
+/// and less than the \a initial_count.
+
+int
+ssx_semaphore_create(SsxSemaphore *semaphore,
+ SsxSemaphoreCount initial_count,
+ SsxSemaphoreCount max_count)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(semaphore == 0, SSX_INVALID_SEMAPHORE_AT_CREATE);
+ SSX_ERROR_IF((max_count != 0) && (initial_count > max_count),
+ SSX_INVALID_ARGUMENT_SEMAPHORE);
+ }
+
+ __ssx_thread_queue_clear(&(semaphore->pending_threads));
+ semaphore->count = initial_count;
+ semaphore->max_count = max_count;
+
+ return SSX_OK;
+}
+
+
+
+
+
diff --git a/src/ssx/ssx/ssx_stack_init.c b/src/ssx/ssx/ssx_stack_init.c
new file mode 100755
index 0000000..9d6331a
--- /dev/null
+++ b/src/ssx/ssx/ssx_stack_init.c
@@ -0,0 +1,87 @@
+// $Id: ssx_stack_init.c,v 1.1.1.1 2013/12/11 21:03:28 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ssx/ssx/ssx_stack_init.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ssx_stack_init.c
+/// \brief SSX stack initialization
+///
+/// The entry points in this file are initialization routines - they are never
+/// needed after SSX initialization and their code space could be reclaimed by
+/// the application after initialization if required.
+///
+/// This code was split out from "ssx_init.c" because it may be needed in a
+/// thread configuration if threads are being created dynamically. in an
+/// interrupt-only configuration it is not needed after \c ssx_initialize().
+
+#include "ssx.h"
+
+/// Initialize a stack area.
+///
+/// \param stack A pointer to the smallest legal address of the stack. The
+/// stack address is modified as the stack is aligned and initialized.
+///
+/// \param size A pointer to the size of the stack (in bytes). The size is
+/// modified as the stack is aligned and initialized. At exit this is the
+/// final usable stack area size aligned to the size of the SSX_STACK_TYPE.
+///
+/// SSX makes no assumptions about size or alignment of the area provided as a
+/// stack, and carefully aligns and initializes the stack. Regardless of how
+/// the stack grows, the \a stack parameter is considered to be the lowest
+/// legal address of the stack.
+
+int
+__ssx_stack_init(SsxAddress *stack,
+ size_t *size)
+{
+ SsxAddress mask;
+ size_t excess, i, count;
+ SSX_STACK_TYPE *p;
+
+ if (SSX_STACK_DIRECTION < 0) {
+
+ // Stacks grow down. The initial stack pointer is set to just above
+ // the last allocated stack address. This is legal for pre-decrement
+ // stacks, otherwise the initial address is first brought into range
+ // before alignment. The stack is aligned downward, then the size is
+ // adjusted to a multiple of the stack type. Stacks are optionally
+ // prepatterned. Alignment is assumed to be a power of 2.
+
+ *stack += *size;
+
+ if (!SSX_STACK_PRE_DECREMENT) {
+ *stack -= sizeof(SSX_STACK_TYPE);
+ *size -= sizeof(SSX_STACK_TYPE);
+ }
+
+ mask = SSX_STACK_ALIGNMENT - 1;
+ excess = *stack & mask;
+ *stack -= excess;
+ *size -= excess;
+ *size = (*size / sizeof(SSX_STACK_TYPE)) * sizeof(SSX_STACK_TYPE);
+
+ if (SSX_STACK_CHECK) {
+ p = (SSX_STACK_TYPE *)(*stack);
+ count = *size / sizeof(SSX_STACK_TYPE);
+ for (i = 0; i < count; i++) {
+ if (SSX_STACK_PRE_DECREMENT) {
+ *(--p) = SSX_STACK_PATTERN;
+ } else {
+ *(p--) = SSX_STACK_PATTERN;
+ }
+ }
+ }
+
+ __ssx_stack_create_initial_frame(stack, size);
+
+ } else {
+
+ SSX_PANIC(SSX_UNIMPLEMENTED);
+ }
+
+ return SSX_OK;
+}
+
diff --git a/src/ssx/ssx/ssx_thread_core.c b/src/ssx/ssx/ssx_thread_core.c
new file mode 100755
index 0000000..d6124e8
--- /dev/null
+++ b/src/ssx/ssx/ssx_thread_core.c
@@ -0,0 +1,946 @@
+// $Id: ssx_thread_core.c,v 1.2 2014/02/03 01:30:44 daviddu Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ssx/ssx/ssx_thread_core.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ssx_thread_core.c
+/// \brief SSX thread APIs
+///
+/// The entry points in this file are considered 'core' routines that will
+/// always be present at runtime in any SSX application that enables threads.
+
+#include "ssx.h"
+
+#define __SSX_THREAD_CORE_C__
+
+
+// This routine is only used locally. Noncritical interrupts must be disabled
+// at entry.
+
+static inline int
+__ssx_thread_is_active(SsxThread *thread)
+{
+ return ((thread->state != SSX_THREAD_STATE_COMPLETED) &&
+ (thread->state != SSX_THREAD_STATE_DELETED));
+}
+
+
+// This routine is only used locally. Noncritical interrupts must be disabled
+// at entry.
+
+static inline int
+__ssx_thread_is_mapped(SsxThread *thread)
+{
+ return (thread->state == SSX_THREAD_STATE_MAPPED);
+}
+
+
+// This routine is only used locally. Noncritical interrupts must be disabled
+// at entry. This is only called on mapped threads.
+
+static inline int
+__ssx_thread_is_runnable(SsxThread *thread)
+{
+ return __ssx_thread_queue_member(&__ssx_run_queue, thread->priority);
+}
+
+
+// This routine is only used locally. Noncritical interrupts must be disabled
+// at entry.
+
+static inline SsxThread*
+__ssx_thread_at_priority(SsxThreadPriority priority)
+{
+ return (SsxThread*)__ssx_priority_map[priority];
+}
+
+
+// This routine is only used locally. Noncritical interrupts must be disabled
+// at entry. The caller must also have checked that the priority is free.
+// This routine is only called on threads known to be in a suspended state,
+// either SSX_THREAD_STATE_SUSPENDED_RUNNABLE or
+// SSX_THREAD_STATE_SUSPENDED_BLOCKED. Mapping a runnable thread adds it to
+// the run queue. Mapping a thread pending on a semaphore either takes the
+// count and becomes runnable or adds the thread to the pending queue for the
+// semaphore. Mapping a sleeping thread requires no further action
+// here. Scheduling after the map must be handled by the caller.
+
+void
+__ssx_thread_map(SsxThread* thread)
+{
+ SsxThreadPriority priority;
+
+ priority = thread->priority;
+ __ssx_priority_map[priority] = thread;
+
+ if (thread->state == SSX_THREAD_STATE_SUSPENDED_RUNNABLE) {
+
+ __ssx_thread_queue_insert(&__ssx_run_queue, priority);
+
+ } else if (thread->flags & SSX_THREAD_FLAG_SEMAPHORE_PEND) {
+
+ if (thread->semaphore->count) {
+
+ thread->semaphore->count--;
+ __ssx_thread_queue_insert(&__ssx_run_queue, priority);
+
+ } else {
+
+ __ssx_thread_queue_insert(&(thread->semaphore->pending_threads),
+ priority);
+ }
+ }
+
+ thread->state = SSX_THREAD_STATE_MAPPED;
+
+ if (SSX_KERNEL_TRACE_ENABLE) {
+ if (__ssx_thread_is_runnable(thread)) {
+ SSX_TRACE_THREAD_MAPPED_RUNNABLE(priority);
+ } else if (thread->flags & SSX_THREAD_FLAG_SEMAPHORE_PEND) {
+ SSX_TRACE_THREAD_MAPPED_SEMAPHORE_PEND(priority);
+ } else {
+ SSX_TRACE_THREAD_MAPPED_SLEEPING(priority);
+ }
+ }
+}
+
+
+// This routine is only used locally. Noncritical interrupts must be disabled
+// at entry. This routine is only ever called on threads in the
+// SSX_THREAD_STATE_MAPPED. Unmapping a thread removes it from the priority
+// map, the run queue and any semaphore pend, but does not cancel any
+// timers. Scheduling must be handled by the code calling
+// __ssx_thread_unmap().
+
+void
+__ssx_thread_unmap(SsxThread *thread)
+{
+ SsxThreadPriority priority;
+
+ priority = thread->priority;
+ __ssx_priority_map[priority] = 0;
+
+ if (__ssx_thread_is_runnable(thread)) {
+
+ thread->state = SSX_THREAD_STATE_SUSPENDED_RUNNABLE;
+ __ssx_thread_queue_delete(&__ssx_run_queue, priority);
+
+ } else {
+
+ thread->state = SSX_THREAD_STATE_SUSPENDED_BLOCKED;
+ if (thread->flags & SSX_THREAD_FLAG_SEMAPHORE_PEND) {
+ __ssx_thread_queue_delete(&(thread->semaphore->pending_threads),
+ priority);
+ }
+ }
+}
+
+
+// Schedule and run the highest-priority mapped runnable thread.
+//
+// The priority of the next thread to run is first computed. This may be
+// SSX_THREADS, indicating that the only thread to run is the idle thread.
+// This will always cause (or defer) a 'context switch' to the idle thread.
+// Otherwise, if the new thread is not equal to the current thread this will
+// also cause (or defer) a context switch. Note that scheduling is defined in
+// terms of priorities but actually implemented in terms of SsxThread pointers.
+//
+// If we are not yet in thread mode we're done - threads will be started by
+// ssx_start_threads() later. If we're in thread context a context switch
+// happens immediately. In an interrupt context the switch is deferred to the
+// end of SSX_NONCRITICAL interrupt processing.
+
+void
+__ssx_schedule(void)
+{
+ __ssx_next_priority = __ssx_thread_queue_min(&__ssx_run_queue);
+ __ssx_next_thread = __ssx_priority_map[__ssx_next_priority];
+
+ if ((__ssx_next_thread == 0) ||
+ (__ssx_next_thread != __ssx_current_thread)) {
+
+ if (__ssx_kernel_mode_thread()) {
+ if (__ssx_kernel_context_thread()) {
+ if (__ssx_current_thread != 0) {
+ __ssx_switch();
+ } else {
+ __ssx_next_thread_resume();
+ }
+ } else {
+ __ssx_delayed_switch = 1;
+ }
+ }
+ }
+}
+
+
+// This routine is only used locally.
+//
+// Completion and deletion are pretty much the same thing. Completion is
+// simply self-deletion of the current thread (which is mapped by
+// definition.) The complete/delete APIs have slightly different error
+// conditions but are otherwise the same.
+//
+// Deleting a mapped thread first unmaps (suspends) the thread, which takes
+// care of removing the thread from any semaphores it may be pending on. Then
+// any outstanding timer is also cancelled.
+//
+// If the current thread is being deleted we install the idle thread as
+// __ssx_current_thread, so scheduling is forced and no context is saved on
+// the context switch.
+//
+// Note that we do not create trace events for unmapped threads since the trace
+// tag only encodes the priority, which may be in use by a mapped thread.
+
+void
+__ssx_thread_delete(SsxThread *thread, SsxThreadState final_state)
+{
+ SsxMachineContext ctx;
+ int mapped;
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ mapped = __ssx_thread_is_mapped(thread);
+
+ if (mapped) {
+ __ssx_thread_unmap(thread);
+ }
+
+ __ssx_timer_cancel(&(thread->timer));
+ thread->state = final_state;
+
+ if (mapped) {
+
+ if (SSX_KERNEL_TRACE_ENABLE) {
+ if (final_state == SSX_THREAD_STATE_DELETED) {
+ SSX_TRACE_THREAD_DELETED(thread->priority);
+ } else {
+ SSX_TRACE_THREAD_COMPLETED(thread->priority);
+ }
+ }
+
+ if (thread == __ssx_current_thread) {
+ __ssx_current_thread = 0;
+ }
+ __ssx_schedule();
+ }
+
+ ssx_critical_section_exit(&ctx);
+}
+
+
+// Generic thread timeout
+//
+// This routine is called as a timer callback either because a sleeping thread
+// has timed out or a thread pending on a semaphore has timed out. If the
+// thread is not already runnable then the the timeout flag is set, and if the
+// thread is mapped it is scheduled.
+//
+// This implementation allows that a thread blocked on a timer may have been
+// made runnable by some other mechanism, such as acquiring a semaphore. In
+// order to provide an iteration-free implementation of
+// ssx_semaphore_release_all(), cancelling any semaphore timeouts is deferred
+// until the thread runs again.
+//
+// __ssx_thread_timeout() is currenly the only timer interrupt called from a
+// critical section.
+//
+// Note that we do not create trace events for unmapped threads since the trace
+// tag only encodes the priority, which may be in use by a mapped thread.
+
+void
+__ssx_thread_timeout(void *arg)
+{
+ SsxThread *thread = (SsxThread *)arg;
+
+ switch (thread->state) {
+
+ case SSX_THREAD_STATE_MAPPED:
+ if (!__ssx_thread_is_runnable(thread)) {
+ thread->flags |= SSX_THREAD_FLAG_TIMED_OUT;
+ __ssx_thread_queue_insert(&__ssx_run_queue, thread->priority);
+ __ssx_schedule();
+ }
+ break;
+
+ case SSX_THREAD_STATE_SUSPENDED_RUNNABLE:
+ break;
+
+ case SSX_THREAD_STATE_SUSPENDED_BLOCKED:
+ thread->flags |= SSX_THREAD_FLAG_TIMED_OUT;
+ thread->state = SSX_THREAD_STATE_SUSPENDED_RUNNABLE;
+ break;
+
+ default:
+ SSX_PANIC(SSX_THREAD_TIMEOUT_STATE);
+ }
+}
+
+
+// This routine serves as a container for the SSX_START_THREADS_HOOK and
+// actually starts threads. The helper routine __ssx_call_ssx_start_threads()
+// arranges this routine to be called with interrupts disabled while running
+// on the noncritical interrupt stack.
+//
+// The reason for this roundabout is that we want to be able to run a hook
+// routine (transparent to the application) that can hand over every last byte
+// of free memory to "malloc()" - including the stack of main(). Since we
+// always need to run on some stack, we chose to run the hook on the kernel
+// noncritical interrupt stack. However to do this safely we need to make sure
+// that no interrupts will happen during this time. When __ssx_thread_resume()
+// is finally called all stack-based context is lost but it doesn't matter at
+// that point - it's a one-way street into thread execution.
+//
+// This is considered part of ssx_start_threads() and so is also considered a
+// 'core' routine.
+
+void
+__ssx_start_threads(void)
+{
+ SSX_START_THREADS_HOOK;
+
+ __ssx_next_thread_resume();
+
+ SSX_PANIC(SSX_START_THREADS_RETURNED);
+}
+
+
+/// Start SSX threads
+///
+/// This routine starts the SSX thread scheduler infrastructure. This routine
+/// must be called after a call of \c ssx_initialize(). This routine never
+/// returns. Interrupt (+ timer) only configurations of SSX need not call this
+/// routine.
+///
+/// Note: This tiny routine is considered a 'core' routine so that the
+/// initialziation code can safely recover all 'init' code space before
+/// starting threads.
+///
+/// This routine typically does not return - any return value indicates an
+/// error; see \ref ssx_errors
+///
+/// \retval -SSX_ILLEGAL_CONTEXT_THREAD The API was called twice.
+
+int
+ssx_start_threads(void)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(__ssx_kernel_mode_thread(), SSX_ILLEGAL_CONTEXT_THREAD);
+ }
+
+ __ssx_call_ssx_start_threads();
+
+ return 0;
+}
+
+
+/// Resume a suspended thread
+///
+/// \param thread The thread to resume
+///
+/// SSX only allows one thread at a time to run at a given priority, and
+/// implements the notion of a thread \e claiming a priority. A suspended
+/// thread claims a priority when it is mapped by a call of
+/// ssx_thread_resume(). This API will succeed only if no other active thread
+/// is currently mapped at the priority assigned to the thread. SSX provides
+/// the ssx_thread_at_priority() API which allows an application-level
+/// scheduler to correctly manage multiple threads running at the same
+/// priority.
+///
+/// If the thread was sleeping while suspended it remains asleep. However if
+/// the sleep timer timed out while the thread was suspended it will be
+/// resumed runnable.
+///
+/// If the thread was blocked on a semaphore when it was suspended, then when
+/// the thread is resumed it will attempt to reacquire the semaphore.
+/// However, if the thread was blocked on a semaphore with timeout while
+/// suspended and the timeout interval has passed, the thread will be resumed
+/// runnable and see that the semaphore pend timed out.
+///
+/// It is not an error to call ssx_thread_resume() on a mapped
+/// thread. However it is an error to call ssx_thread_resume() on a completed
+/// or deleted thread.
+///
+/// Return values other than SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion, including calls on a \a thread that is
+/// already mapped.
+///
+/// \retval -SSX_ILLEGAL_CONTEXT_THREAD The API was called
+/// from a critical interrupt context.
+///
+/// \retval -SSX_INVALID_THREAD_AT_RESUME1 The \a thread is a null (0) pointer.
+///
+/// \retval -SSX_INVALID_THREAD_AT_RESUME2 The \a thread is not active,
+/// i.e. has completed or been deleted.
+///
+/// \retval -SSX_PRIORITY_IN_USE_AT_RESUME Another thread is already mapped at
+/// the priority of the \a thread.
+
+int
+ssx_thread_resume(SsxThread *thread)
+{
+ SsxMachineContext ctx;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF_CRITICAL_INTERRUPT_CONTEXT();
+ SSX_ERROR_IF(thread == 0, SSX_INVALID_THREAD_AT_RESUME1);
+ }
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF_CRITICAL(!__ssx_thread_is_active(thread),
+ SSX_INVALID_THREAD_AT_RESUME2,
+ &ctx);
+ }
+
+ if (!__ssx_thread_is_mapped(thread)) {
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF_CRITICAL(__ssx_priority_map[thread->priority] != 0,
+ SSX_PRIORITY_IN_USE_AT_RESUME,
+ &ctx);
+ }
+ __ssx_thread_map(thread);
+ __ssx_schedule();
+ }
+
+ ssx_critical_section_exit(&ctx);
+
+ return SSX_OK;
+}
+
+
+/// Suspend a thread
+///
+/// Any active thread can be suspended. A suspended thread 1) remains active
+/// but will not be scheduled; 2) relinquishes its priority assignment,
+/// allowing another thread to be resumed at the suspended thread's priority;
+/// and 3) disassociates from any semaphore mutual exclusion it may have been
+/// participating in.
+///
+/// If a sleeping thread is suspended, the sleep timer remains active but a
+/// timeout of the timer simply marks the thread as runnable, but does not
+/// resume the thread.
+///
+/// If a thread blocked on a semaphore is suspended, the thread no longer
+/// participates in the semaphore mutual exclusion. If the thread is later
+/// resumed it will attempt to acquire the semaphore again the next time it
+/// runs (unless it was blocked with a timeout and the timeout has expired).
+///
+/// If a thread blocked on a semaphore with timeout is suspended, the
+/// semaphore timeout timer continues to run. If the timer times out while the
+/// thread is suspended the thread is simply marked runnable. If the thread is
+/// later resumed, the suspended call of \c ssx_semaphore_pend() will return the
+/// timeout code -SSX_SEMAPHORE_PEND_TIMED_OUT.
+///
+/// Return values other than SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion, including calls on a \a thread that is
+/// already suspended.
+///
+/// \retval -SSX_ILLEGAL_CONTEXT_THREAD The API was called from a critical
+/// interrupt context.
+///
+/// \retval -SSX_INVALID_THREAD_AT_SUSPEND1 The \a thread is a null (0) pointer
+///
+/// \retval -SSX_INVALID_THREAD_AT_SUSPEND2 The \a thread is not active,
+/// i.e. has completed or been deleted.
+
+int
+ssx_thread_suspend(SsxThread *thread)
+{
+ SsxMachineContext ctx;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF_CRITICAL_INTERRUPT_CONTEXT();
+ SSX_ERROR_IF((thread == 0), SSX_INVALID_THREAD_AT_SUSPEND1);
+ }
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF_CRITICAL(!__ssx_thread_is_active(thread),
+ SSX_INVALID_THREAD_AT_SUSPEND2,
+ &ctx);
+ }
+
+ if (__ssx_thread_is_mapped(thread)) {
+
+ SSX_TRACE_THREAD_SUSPENDED(thread->priority);
+ __ssx_thread_unmap(thread);
+ __ssx_schedule();
+ }
+
+ ssx_critical_section_exit(&ctx);
+
+ return SSX_OK;
+}
+
+
+/// Delete a thread
+///
+/// Any active thread can be deleted. If a thread is deleted it is removed
+/// from the run queue, deleted from the timer queue (if sleeping or blocked
+/// on a semaphore with timeout), and deleted from the semaphore mutual
+/// exclusion if blocked on a semaphore. The thread control block is then
+/// marked as deleted.
+///
+/// Once a thread has completed or been deleted the thread structure and
+/// thread stack areas can be used for other purposes.
+///
+/// \param thread The thread to delete
+///
+/// Return values other than SSX_OK (0) are errors; see \ref ssx_errors. If a
+/// thread deletes itself this API does not return at all.
+///
+/// \retval 0 Successful completion, including calls on a \a thread that has
+/// completed or had already been deleted.
+///
+/// \retval -SSX_ILLEGAL_CONTEXT_THREAD The API was called from a critical
+/// interrupt context.
+///
+/// \retval -SSX_INVALID_THREAD_AT_DELETE The \a thread is a null (0) pointer.
+
+int
+ssx_thread_delete(SsxThread *thread)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF_CRITICAL_INTERRUPT_CONTEXT();
+ SSX_ERROR_IF(thread == 0, SSX_INVALID_THREAD_AT_DELETE);
+ }
+
+ __ssx_thread_delete(thread, SSX_THREAD_STATE_DELETED);
+
+ return SSX_OK;
+}
+
+
+/// Complete a thread
+///
+/// If a thread ever returns from the subroutine defining the thread entry
+/// point, the thread is removed from all SSX kernel data structures and
+/// marked completed. The thread routine can also use the API ssx_complete()
+/// to make this more explicit if desired. SSX makes no distinction between
+/// completed and deleted threads, but provides these indications for
+/// the benefit of the application.
+///
+/// Note that this API is only available from the current thread to mark its
+/// own completion.
+///
+/// Once a thread has completed or been deleted the thread structure and
+/// thread stack areas can be used for other purposes.
+///
+/// Any return value indicates an error; see \ref ssx_errors. In the event of
+/// a successful completion this API does not return to the caller, which is
+/// always the thread context being completed.
+///
+/// \retval -SSX_ILLEGAL_CONTEXT_THREAD The API was not called from a thread
+/// context.
+
+// Note: Casting __ssx_current_thread removes the 'volatile' attribute.
+
+int
+ssx_complete(void)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_UNLESS_THREAD_CONTEXT();
+ }
+
+ __ssx_thread_delete((SsxThread *)__ssx_current_thread,
+ SSX_THREAD_STATE_COMPLETED);
+
+ return SSX_OK;
+}
+
+
+/// Sleep a thread until an absolute time
+///
+/// \param time An absolute time as measured by the SSX timebase
+///
+/// Threads can use this API to sleep until an absolute time. Sleeping threads
+/// are not scheduled, although they maintain their priorities. This differs
+/// from thread suspension, where the suspended thread relinquishes its
+/// priority. When the sleep timer times out the thread becomes runnable
+/// again, and will run as soon as it becomes the highest-priority mapped
+/// runnable thread.
+///
+/// Sleeping threads may also be later suspended. In this case the Sleep timer
+/// continues to run, and if it times out before the thread is resumed the
+/// thread will be immediately runnable when it is resumed.
+///
+/// See the SSX specification for a full discussion of how SSX handles
+/// scheduling events at absolute times "in the past". Briefly stated, if the
+/// \a time is in the past, the thread will Sleep for the briefest possible
+/// period supported by the hardware.
+///
+/// Return values other than SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion.
+///
+/// \retval -SSX_ILLEGAL_CONTEXT_THREAD The API was not called from a thread
+/// context.
+
+// Note: Casting __ssx_current_thread removes the 'volatile' attribute.
+
+int
+ssx_sleep_absolute(SsxTimebase time)
+{
+ SsxMachineContext ctx;
+ SsxThread *current;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_UNLESS_THREAD_CONTEXT();
+ }
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ current = (SsxThread *)__ssx_current_thread;
+
+ current->timer.timeout = time;
+ __ssx_timer_schedule(&(current->timer));
+
+ current->flags |= SSX_THREAD_FLAG_TIMER_PEND;
+
+ SSX_TRACE_THREAD_SLEEP(current->priority);
+
+ __ssx_thread_queue_delete(&__ssx_run_queue, current->priority);
+ __ssx_schedule();
+
+ current->flags &= ~(SSX_THREAD_FLAG_TIMER_PEND | SSX_THREAD_FLAG_TIMED_OUT);
+
+ ssx_critical_section_exit(&ctx);
+
+ return SSX_OK;
+}
+
+/// Sleep a thread for an interval relative to the current time.
+///
+/// \param interval A time interval relative to the current timebase.
+///
+/// Threads can use this API to sleep for a time relative to the current
+/// timebase. The absolute timeout is \c ssx_timebase_get() + \a interval.
+///
+/// Sleeping threads are not scheduled, although they maintain their
+/// priorities. This differs from thread suspension, where the suspended
+/// thread relinquishes its priority. When the sleep timer times out the
+/// thread becomes runnable again, and will run as soon as it becomes the
+/// highest-priority mapped runnable thread.
+///
+/// Sleeping threads may also be later suspended. In this case the Sleep timer
+/// continues to run, and if it times out before the thread is resumed the
+/// thread will be immediately runnable when it is resumed.
+///
+/// See the SSX specification for a full discussion of how SSX handles
+/// scheduling events at absolute times "in the past". Briefly stated, if the
+/// \a interval is 0 or is so small that the absolute time becomes a "past"
+/// time before the Sleep is actually scheduled, the thread will Sleep for the
+/// briefest possible period supported by the hardware.
+///
+/// Return values other than SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion.
+///
+/// \retval -SSX_ILLEGAL_CONTEXT_THREAD The API was not called from a thread
+/// context.
+
+int
+ssx_sleep(SsxInterval interval)
+{
+ return ssx_sleep_absolute(ssx_timebase_get() + interval);
+}
+
+
+/// Get information about a thread.
+///
+/// \param thread A pointer to the SsxThread to query
+///
+/// \param state The value returned through this pointer is the current state
+/// of the thread; See \ref ssx_thread_states. The caller can set this
+/// parameter to the null pointer (0) if this information is not required.
+///
+/// \param priority The value returned through this pointer is the current
+/// priority of the thread. The caller can set this parameter to the null
+/// pointer (0) if this information is not required.
+///
+/// \param runnable The value returned through this pointer is 1 if the thread
+/// is in state SSX_THREAD_STATE_MAPPED and is currently in the run queue
+/// (i.e., neither blocked on a semaphore nor sleeping), otherwise 0. The
+/// caller can set this parameter to the null pointer (0) if this information
+/// is not required.
+///
+/// The information returned by this API can only be guaranteed consistent if
+/// the API is called from an SSX_NONCRITICAL critical section. Since the
+/// implementation of this API does not enforce a critical section, it is not
+/// an error to call this API from a critical interrupt context.
+///
+/// Return values other than SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SSX_INVALID_THREAD_AT_INFO The \a thread is a null (0) pointer.
+
+int
+ssx_thread_info_get(SsxThread *thread,
+ SsxThreadState *state,
+ SsxThreadPriority *priority,
+ int *runnable)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(thread == 0, SSX_INVALID_THREAD_AT_INFO);
+ }
+
+ if (state) {
+ *state = thread->state;
+ }
+ if (priority) {
+ *priority = thread->priority;
+ }
+ if (runnable) {
+ *runnable = ((thread->state == SSX_THREAD_STATE_MAPPED) &&
+ __ssx_thread_queue_member(&__ssx_run_queue,
+ thread->priority));
+ }
+ return SSX_OK;
+}
+
+
+/// Change the priority of a thread.
+///
+/// \param thread The thread whose priority will be changed
+///
+/// \param new_priority The new priority of the thread
+///
+/// \param old_priority The value returned through this pointer is the
+/// old priority of the thread prior to the change. The caller can set
+/// this parameter to the null pointer (0) if this information is not
+/// required.
+///
+/// Thread priorities can be changed by the \c ssx_thread_priority_change()
+/// API. This call will fail if the thread pointer is invalid or if the thread
+/// is mapped and the new priority is currently in use. The call will succeed
+/// even if the \a thread is suspended, completed or deleted. The
+/// application-level scheduling algorithm is completely responsible for the
+/// correctness of the application in the event of suspended, completed or
+/// deleted threads.
+///
+/// Return values other than SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion, including the redundant case of
+/// attempting to change the priority of the thread to its current priority.
+///
+/// \retval -SSX_ILLEGAL_CONTEXT_THREAD the API was called from a critical
+/// interrupt context.
+///
+/// \retval -SSX_INVALID_THREAD_AT_CHANGE The \a thread is null (0) or
+/// otherwise invalid.
+///
+/// \retval -SSX_INVALID_ARGUMENT_THREAD_CHANGE The \a new_priority is invalid.
+///
+/// \retval -SSX_PRIORITY_IN_USE_AT_CHANGE The \a thread is mapped and the \a
+/// new_priority is currently in use by another thread.
+
+int
+ssx_thread_priority_change(SsxThread *thread,
+ SsxThreadPriority new_priority,
+ SsxThreadPriority *old_priority)
+{
+ SsxMachineContext ctx;
+ SsxThreadPriority priority;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF_CRITICAL_INTERRUPT_CONTEXT();
+ SSX_ERROR_IF(thread == 0, SSX_INVALID_THREAD_AT_CHANGE);
+ SSX_ERROR_IF(new_priority > SSX_THREADS,
+ SSX_INVALID_ARGUMENT_THREAD_CHANGE);
+ }
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ priority = thread->priority;
+
+ if (priority != new_priority) {
+
+ if (!__ssx_thread_is_mapped(thread)) {
+
+ thread->priority = new_priority;
+
+ } else {
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF_CRITICAL(__ssx_priority_map[new_priority] != 0,
+ SSX_PRIORITY_IN_USE_AT_CHANGE,
+ &ctx);
+ }
+
+ __ssx_thread_unmap(thread);
+ thread->priority = new_priority;
+ __ssx_thread_map(thread);
+ __ssx_schedule();
+ }
+ }
+
+ if (old_priority) {
+ *old_priority = priority;
+ }
+
+ ssx_critical_section_exit(&ctx);
+
+ return SSX_OK;
+}
+
+
+/// Return a pointer to the thread (if any) mapped at a given priority.
+///
+/// \param priority The thread priority of interest
+///
+/// \param thread The value returned through this pointer is a pointer to the
+/// thread currently mapped at the given priority level. If no thread is
+/// mapped, or if the \a priority is the priority of the idle thread, the
+/// pointer returned will be null (0).
+///
+/// The information returned by this API can only be guaranteed consistent if
+/// the API is called from an SSX_NONCRITICAL critical section. Since the
+/// implementation of this API does not require a critical section, it is not
+/// an error to call this API from a critical interrupt context.
+///
+/// Return values other than SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion.
+///
+/// \retval -SSX_INVALID_ARGUMENT_THREAD_PRIORITY The \a priority is invalid
+/// or the \a thread parameter is null (0).
+
+int
+ssx_thread_at_priority(SsxThreadPriority priority,
+ SsxThread **thread)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF((priority > SSX_THREADS) || (thread == 0),
+ SSX_INVALID_ARGUMENT_THREAD_PRIORITY);
+ }
+
+ *thread = __ssx_thread_at_priority(priority);
+
+ return SSX_OK;
+}
+
+
+/// Swap thread priorities
+///
+/// \param thread_a A pointer to an initialized SsxThread
+///
+/// \param thread_b A pointer to an initialized SsxThread
+///
+/// This API swaps the priorities of \a thread_a and \a thread_b. The API is
+/// provided to support general and efficient application-directed scheduling
+/// algorithms. The requirements on the \a thread_a and \a thread_b arguments
+/// are that they are valid pointers to initialized SsxThread structures, that
+/// the current thread priorities of both threads are legal, and that if a
+/// thread is currently mapped, that the new thread priority is not otherwise
+/// in use.
+///
+/// The API does not require either thread to be mapped, or even to be active.
+/// It is legal for one or both of the swap partners to be suspended, deleted
+/// or completed threads. The application is completely responsible for the
+/// correctness of scheduling algorithms that might operate on inactive or
+/// suspended threads.
+///
+/// The API does not change the mapped status of a thread. A thread will be
+/// mapped after the call of ssx_thread_priority_swap() if and only if it was
+/// mapped prior to the call. If the new priority of a mapped thread is
+/// currently in use (by a thread other than the swap partner), then the
+/// SSX_PRIORITY_IN_USE_AT_SWAP error is signalled and the swap does not take
+/// place. This could only happen if the swap partner is not currently mapped.
+///
+/// It is legal for a thread to swap its own priority with another thread. The
+/// degenerate case that \a thread_a and \a thread_b are equal is also legal -
+/// but has no effect.
+///
+/// Return values other than SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion, including the redundant cases that do not
+/// actually change priorities, or the cases that assign new priorities to
+/// suspended, completed or deleted threads.
+///
+/// \retval -SSX_ILLEGAL_CONTEXT_THREAD the API was called from a critical
+/// interrupt context.
+///
+/// \retval -SSX_INVALID_THREAD_AT_SWAP1 One or both of \a thread_a and
+/// \a thread_b is null (0) or otherwise invalid,
+///
+/// \retval -SSX_INVALID_THREAD_AT_SWAP2 the priorities of One or both of
+/// \a thread_a and \a thread_b are invalid.
+///
+/// \retval -SSX_INVALID_ARGUMENT One or both of the priorities
+/// of \a thread_a and \a thread_b is invalid.
+///
+/// \retval -SSX_PRIORITY_IN_USE_AT_SWAP Returned if a thread is mapped and the
+/// new thread priority is currently in use by another thread (other than the
+/// swap partner).
+
+int
+ssx_thread_priority_swap(SsxThread* thread_a, SsxThread* thread_b)
+{
+ SsxMachineContext ctx;
+ SsxThreadPriority priority_a, priority_b;
+ int mapped_a, mapped_b;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF_CRITICAL_INTERRUPT_CONTEXT();
+ SSX_ERROR_IF((thread_a == 0) || (thread_b == 0),
+ SSX_INVALID_THREAD_AT_SWAP1);
+ }
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ if (thread_a != thread_b) {
+
+ mapped_a = __ssx_thread_is_mapped(thread_a);
+ mapped_b = __ssx_thread_is_mapped(thread_b);
+ priority_a = thread_a->priority;
+ priority_b = thread_b->priority;
+
+ if (SSX_ERROR_CHECK_API) {
+ int priority_in_use;
+ SSX_ERROR_IF_CRITICAL((priority_a > SSX_THREADS) ||
+ (priority_b > SSX_THREADS),
+ SSX_INVALID_THREAD_AT_SWAP2,
+ &ctx);
+ priority_in_use =
+ (mapped_a && !mapped_b &&
+ (__ssx_thread_at_priority(priority_b) != 0)) ||
+ (!mapped_a && mapped_b &&
+ (__ssx_thread_at_priority(priority_a) != 0));
+ SSX_ERROR_IF_CRITICAL(priority_in_use,
+ SSX_PRIORITY_IN_USE_AT_SWAP, &ctx);
+ }
+
+ if (mapped_a) {
+ __ssx_thread_unmap(thread_a);
+ }
+ if (mapped_b) {
+ __ssx_thread_unmap(thread_b);
+ }
+ thread_a->priority = priority_b;
+ thread_b->priority = priority_a;
+ if (mapped_a) {
+ __ssx_thread_map(thread_a);
+ }
+ if (mapped_b) {
+ __ssx_thread_map(thread_b);
+ }
+ __ssx_schedule();
+ }
+
+ ssx_critical_section_exit(&ctx);
+
+ return SSX_OK;
+}
+
+
+#undef __SSX_THREAD_CORE_C__
diff --git a/src/ssx/ssx/ssx_thread_init.c b/src/ssx/ssx/ssx_thread_init.c
new file mode 100755
index 0000000..c1a71b5
--- /dev/null
+++ b/src/ssx/ssx/ssx_thread_init.c
@@ -0,0 +1,140 @@
+// $Id: ssx_thread_init.c,v 1.2 2014/02/03 01:30:44 daviddu Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ssx/ssx/ssx_thread_init.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ssx_thread_init.c
+/// \brief SSX thread API initialization routines
+///
+/// The entry points in this file are routines that are typically used during
+/// initialization, and their code space could be deallocated and recovered if
+/// no longer needed by the application after initialization.
+
+#include "ssx.h"
+
+/// Create (initialize) a thread
+///
+/// \param thread A pointer to an SsxThread structure to initialize
+///
+/// \param thread_routine The subroutine that implements the thread
+///
+/// \param arg Private data to be passed as the argument to the thread
+/// routine when it begins execution
+///
+/// \param stack The stack space of the thread
+///
+/// \param stack_size The size of the stack in bytes
+///
+/// \param priority The initial priority of the thread
+///
+/// The \a thread argument must be a pointer to an uninitialized or completed
+/// or deleted thread. This \c SsxThread structure \em is the thread, so this
+/// memory area must not be modified by the application until the thread
+/// completes or is deleted. SSX can not tell if an SsxThread structure is
+/// currently in use as a thread control block.ssx_thread_create() will
+/// silently overwrite an SsxThread structure that is currently in use.
+///
+/// The stack area must be large enough to hold the dynamic stack requirements
+/// of the entry point routine, and all subroutines and functions that might
+/// be invoked on any path from the entry point. The stack must also always
+/// be able to hold the thread context in the event the thread is preempted,
+/// plus other critical context. SSX aligns stack areas in machine-specific
+/// ways, so that the actual stack area may reduced in size slightly if it is
+/// not already aligned.
+///
+/// Threads are created runnable but unmapped. A newly created thread will
+/// not be eligible to run until a call of ssx_thread_resume() targets the
+/// thread.
+///
+/// Return values other than SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SSX_INVALID_THREAD_AT_CREATE The \a thread is a null (0) pointer.
+///
+/// \retval -SSX_ILLEGAL_CONTEXT The API was called from a critical interrupt
+/// context.
+///
+/// \retval -SSX_INVALID_ARGUMENT_THREAD1 the \a thread_routine is null (0)
+///
+/// \retval -SSX_INVALID_ARGUMENT_THREAD2 the \a priority is invalid,
+///
+/// \retval -SSX_INVALID_ARGUMENT_THREAD3 the stack area wraps around
+/// the end of memory.
+///
+/// \retval -SSX_STACK_OVERFLOW The stack area at thread creation is smaller
+/// than the minimum safe size.
+
+int
+ssx_thread_create(SsxThread *thread,
+ SsxThreadRoutine thread_routine,
+ void *arg,
+ SsxAddress stack,
+ size_t stack_size,
+ SsxThreadPriority priority)
+{
+ int rc;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF_CRITICAL_INTERRUPT_CONTEXT();
+ SSX_ERROR_IF(thread == 0, SSX_INVALID_THREAD_AT_CREATE);
+ SSX_ERROR_IF((thread_routine == 0) ||
+ (priority >= SSX_THREADS),
+ SSX_INVALID_ARGUMENT_THREAD1);
+ }
+
+ rc = __ssx_stack_init(&stack, &stack_size);
+ if (rc) {
+ return rc;
+ }
+
+ thread->saved_stack_pointer = stack;
+ thread->stack_base = stack;
+
+ if (SSX_STACK_DIRECTION < 0) {
+
+ thread->stack_limit = stack - stack_size;
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(thread->stack_limit > thread->stack_base,
+ SSX_INVALID_ARGUMENT_THREAD2);
+ }
+
+ } else {
+
+ thread->stack_limit = stack + stack_size;
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(thread->stack_limit < thread->stack_base,
+ SSX_INVALID_ARGUMENT_THREAD3);
+ }
+ }
+
+ thread->semaphore = 0;
+ thread->priority = priority;
+ thread->state = SSX_THREAD_STATE_SUSPENDED_RUNNABLE;
+ thread->flags = 0;
+
+ ssx_timer_create_nonpreemptible(&(thread->timer),
+ __ssx_thread_timeout,
+ (void *)thread);
+
+ __ssx_thread_context_initialize(thread, thread_routine, arg);
+
+ return rc;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/ssx/ssx/ssx_timer_core.c b/src/ssx/ssx/ssx_timer_core.c
new file mode 100755
index 0000000..8153acf
--- /dev/null
+++ b/src/ssx/ssx/ssx_timer_core.c
@@ -0,0 +1,447 @@
+// $Id: ssx_timer_core.c,v 1.2 2014/02/03 01:30:44 daviddu Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ssx/ssx/ssx_timer_core.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ssx_timer_core.c
+/// \brief SSX portable kernel timer handler
+///
+/// This file contains core routines that would be needed by any application
+/// that requires SSX timer support at runtime.
+///
+/// SSX implements a 'tickless' kernel - all events are scheduled at absolute
+/// times of the SSX timebase. This approach gives the application full
+/// control over granularity of event scheduling. Scheduling in absolute time
+/// opens up the possibility of scheduling events "in the past". SSX
+/// uniformly handles this case by scheduling "past" events to occur 1
+/// timebase tick in the future, so that timer callbacks are always run in the
+/// expected noncritical interrupt context.
+///
+/// SSX implements the time queue as a simple unordered list of events, plus a
+/// dedicated variable that holds the earliest timeout of any event in the
+/// list. This is thought to be an appropriate data structure for the
+/// following reasons:
+///
+/// - SSX applications will be small and will not schedule a large number of
+/// events. Therefore the cost of scanning the list each time an event times
+/// out is balanced against the cost of maintaining the list as a sorted data
+/// structure each time an event is added or removed from the event queue.
+///
+/// - SSX applications may schedule and cancel many, many more events (safety
+/// timeouts) than are ever allowed to expire. Events can be added and deleted
+/// from the simple DEQUE very quickly since there is no sorting
+/// overhead.
+///
+/// Events are added to the queue simply by placing them at the end of the
+/// queue. If the new event times out earlier than the previous earliest
+/// event, the hardware timeout is rescheduled for the new event time. Events
+/// are deleted from the queue (cancelled) simply by deleting them. Deletion
+/// does not affect the hardware timeout, even if the deleted event would have
+/// been the next to time out. It is not an error for the timer handler to
+/// take a timer interrupt and find no events pending. Pending events can
+/// also be rescheduled in place.
+///
+/// When a timeout occurs the event list is scanned from the beginning, and
+/// any event that has timed out is rescheduled if necessary (periodic events)
+/// and its callback is processed. Since event and callback processing take
+/// time, the list is potentially scanned multiple times until there are no
+/// more timed-out events in the list.
+///
+/// Note that callbacks are not necessarily processed in time-order. In this
+/// sense the SSX time queue is like a traditional tick-based time queue in
+/// that events are effectively lumped into groups of events that time out
+/// together. In a tick-based kernel the 'lump' is the tick interval; here
+/// the 'lump' is a variable interval that corresponds to the time it takes to
+/// process the entire event list.
+///
+/// Timer callbacks are typically run with interrupt preemption enabled.
+/// Special callbacks may run without preemption. This is the only part of
+/// the SSX kernel where data structures of indeterminate size are processed.
+/// During processing of the event list by the timer interrupt handler, the
+/// consideration of each event always includes a window of preemptability.
+
+#define __SSX_TIMER_CORE_C__
+
+#include "ssx.h"
+
+// This routine is only used in this file, and will always be called in
+// critical section.
+
+static inline int
+timer_active(SsxTimer* timer)
+{
+ return ssx_deque_is_queued((SsxDeque*)timer);
+}
+
+
+// This is the kernel version of ssx_timer_cancel().
+//
+// This routine is used here and by thread and semaphore routines.
+// Noncritical interrupts must be disabled at entry.
+//
+// If the timer is active, then there is a special case if we are going to
+// delete the 'cursor' - that is the timer that __ssx_timer_handler() is going
+// to handle next. In this case we need to move the cursor to the next timer
+// in the queue.
+//
+// Note that cancelling a timer does not cause a re-evaluation of the next
+// timeout. This will happen naturally when the current timeout expires.
+
+int
+__ssx_timer_cancel(SsxTimer *timer)
+{
+ int rc;
+ SsxDeque* timer_deque = (SsxDeque*)timer;
+ SsxTimeQueue* tq = &__ssx_time_queue;
+
+ if (!timer_active(timer)) {
+
+ rc = -SSX_TIMER_NOT_ACTIVE;
+
+ } else {
+
+ if (timer_deque == tq->cursor) {
+ tq->cursor = tq->cursor->next;
+ }
+ ssx_deque_delete(timer_deque);
+ rc = 0;
+ }
+ return rc;
+}
+
+
+// This is the kernel version of ssx_timer_schedule().
+//
+// This routine is used here and by thread and semaphore routines.
+// Noncritical interrupts must be disabled at entry.
+//
+// Unless the timer is already active it is enqueued in the doubly-linked
+// timer list by inserting the timer at the end of the queue. Then the
+// hardware timeout is scheduled if necessary. If the time queue 'cursor' != 0
+// we are in the midst of processing the time queue, and the end of time queue
+// processing will schedule the next hardware timemout.
+
+void
+__ssx_timer_schedule(SsxTimer* timer)
+{
+ SsxTimeQueue* tq = &__ssx_time_queue;
+
+ if (!timer_active(timer)) {
+ ssx_deque_push_back((SsxDeque*)tq, (SsxDeque*)timer);
+ }
+
+ if (timer->timeout < tq->next_timeout) {
+ tq->next_timeout = timer->timeout;
+ if (tq->cursor == 0) {
+ __ssx_schedule_hardware_timeout(tq->next_timeout);
+ }
+ }
+}
+
+
+// The tickless timer mechanism has timed out. Note that due to timer
+// deletions and other factors, there may not actually be a timer in the queue
+// that has timed out - but it doesn't matter (other than for efficiency).
+//
+// Noncritical interrupts are (must be) disabled at entry, and this invariant
+// is checked. This routine must not be entered reentrantly.
+//
+// First, time out any timers that have expired. Timers in the queue are
+// unordered, so we have to check every one. Since passing through the
+// loop takes time, we may have to make multiple passes until we know
+// that there are no timers in the queue that have already timed
+// out. Note that it would also work to only go through the loop once and
+// let the hardware scheduler take care of looping, but that would imply
+// more overhead than the current implementation.
+//
+// On each pass through the loop tq->next_timeout computes the minimum timeout
+// of events remaining in the queue. This is the only part of the kernel that
+// searches a list of indefinite length. Kernel interrupt latency is mitigated
+// by running callbacks with interrupts disabled either during or after the
+// call for timed out events, and also after every check for events that have
+// not timed out.
+//
+// Because interrupt preemption is enabled during processing, and preempting
+// handlers may invoke time queue operations, we need to establish a pointer
+// to the next entry to be examined (tq->cursor) before enabling interupts.
+// It's possible that this pointer will be changed by other interrupt handlers
+// that cancel the timer pointed to by tq->cursor.
+//
+// The main loop iterates on the SsxDeque form of the time queue, casting each
+// element back up to the SsxTimer as it is processed.
+
+void
+__ssx_timer_handler()
+{
+ SsxTimeQueue* tq;
+ SsxTimebase now;
+ SsxTimer* timer;
+ SsxDeque* timer_deque;
+ SsxTimerCallback callback;
+
+ tq = &__ssx_time_queue;
+
+ if (SSX_ERROR_CHECK_KERNEL) {
+ if (tq->cursor != 0) {
+ SSX_PANIC(SSX_TIMER_HANDLER_INVARIANT);
+ }
+ }
+
+ while ((now = ssx_timebase_get()) >= tq->next_timeout) {
+
+ tq->next_timeout = SSX_TIMEBASE_MAX;
+ timer_deque = ((SsxDeque*)tq)->next;
+
+ while (timer_deque != (SsxDeque*)tq) {
+
+ timer = (SsxTimer*)timer_deque;
+ tq->cursor = timer_deque->next;
+
+ if (timer->timeout <= now) {
+
+ // The timer timed out. It is removed from the queue unless
+ // it is a peridic timer that needs to be rescheduled. We do
+ // rescheduling here in the critical section to correctly
+ // handle timers whose callbacks may cancel the timer. The
+ // timer is rescheduled in absolute time.
+ //
+ // The callback may be made with interrupt preemption enabled
+ // or disabled. However to mitigate kernel interrupt latency
+ // we go ahead and open up to interrupts after the callback if
+ // the callback itself was not preemptible.
+
+ if (timer->period == 0) {
+ ssx_deque_delete(timer_deque);
+ } else {
+ timer->timeout += timer->period;
+ tq->next_timeout = MIN(timer->timeout, tq->next_timeout);
+ }
+
+ callback = timer->callback;
+ if (callback) {
+ if (timer->options & SSX_TIMER_CALLBACK_PREEMPTIBLE) {
+ ssx_interrupt_preemption_enable();
+ callback(timer->arg);
+ } else {
+ callback(timer->arg);
+ ssx_interrupt_preemption_enable();
+ }
+ }
+ ssx_interrupt_preemption_disable();
+
+ } else {
+
+ // This timer has not timed out. Its timeout will simply
+ // participate in the computation of the next timeout. For
+ // interrupt latency reasons we always allow a period of
+ // interrupt preemption.
+
+ tq->next_timeout = MIN(timer->timeout, tq->next_timeout);
+ ssx_interrupt_preemption_enable();
+ ssx_interrupt_preemption_disable();
+ }
+
+ timer_deque = tq->cursor;
+ }
+ }
+
+ tq->cursor = 0;
+
+ // Finally, reschedule the next timeout
+
+ __ssx_schedule_hardware_timeout(tq->next_timeout);
+}
+
+
+/// Schedule a timer in absolute time.
+///
+/// \param timer The SsxTimer to schedule.
+///
+/// \param timeout The timer will be scheduled to time out at this absolute
+/// time. Note that if the \a timeout is less than the current time then the
+/// timer will be scheduled at a minimum timeout in the future and the
+/// callback will be executed in an interrupt context.
+///
+/// \param period If non-0, then when the timer times out it will rescheduled
+/// to time out again at the absolute time equal to the last timeout time plus
+/// the \a period. By convention a \a period of 0 indicates a one-shot
+/// timer that is not rescheduled.
+///
+/// Once created with ssx_timer_create() a timer can be \e scheduled, which
+/// queues the timer in the kernel time queue. It is not an error to call
+/// ssx_timer_schedule() on a timer that is already scheduled in the time
+/// queue - the timer is simply rescheduled with the new characteristics.
+///
+/// Return values other than SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SSX_INVALID_TIMER_AT_SCHEDULE A a null (0) pointer was provided as
+/// the \a timer argument.
+///
+/// \retval -SSX_ILLEGAL_CONTEXT_TIMER The call was made from a critical
+/// interrupt context.
+
+int
+ssx_timer_schedule_absolute(SsxTimer *timer,
+ SsxTimebase timeout,
+ SsxInterval period)
+
+{
+ SsxMachineContext ctx;
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(timer == 0, SSX_INVALID_TIMER_AT_SCHEDULE);
+ SSX_ERROR_IF(__ssx_kernel_context_critical_interrupt(),
+ SSX_ILLEGAL_CONTEXT_TIMER);
+ }
+
+ timer->timeout = timeout;
+ timer->period = period;
+ __ssx_timer_schedule(timer);
+
+ ssx_critical_section_exit(&ctx);
+
+ return SSX_OK;
+}
+
+
+/// Schedule a timer for an interval relative to the current time.
+///
+/// \param timer The SsxTimer to schedule.
+///
+/// \param interval The timer will be scheduled to time out at the current
+/// time (ssx_timebase_get()) plus this \a interval.
+///
+/// \param period If non-0, then when the timer times out it will rescheduled
+/// to time out again at the absolute time equal to the last timeout time plus
+/// the \a period. By convention a \a period of 0 indicates a one-shot
+/// timer that is not rescheduled.
+///
+/// Once created with ssx_timer_create() a timer can be \e scheduled, which
+/// queues the timer in the kernel time queue. It is not an error to call \c
+/// ssx_timer_schedule() on a timer that is already scheduled in the time
+/// queue - the timer is simply rescheduled with the new characteristics.
+///
+/// Return values other than SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SSX_INVALID_TIMER_AT_SCHEDULE A a null (0) pointer was provided as
+/// the \a timer argument.
+///
+/// \retval -SSX_ILLEGAL_CONTEXT_TIMER The call was made from a critical
+/// interrupt context.
+
+int
+ssx_timer_schedule(SsxTimer *timer,
+ SsxInterval interval,
+ SsxInterval period)
+{
+ return ssx_timer_schedule_absolute(timer,
+ ssx_timebase_get() + interval,
+ period);
+}
+
+
+/// Cancel (dequeue) a timer.
+///
+/// \param timer The SsxTimer to cancel.
+///
+/// Timers can be canceled at any time. It is never an error to call
+/// ssx_timer_cancel() on an SsxTimer object after it is created. Memory used
+/// by an SsxTimer can be safely reused for another purpose after a successful
+/// call ofssx_timer_cancel().
+///
+/// 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 \a timer is not currently scheduled,
+/// i.e. it was never scheduled or has timed out. This code is returned for
+/// information only and is not considered an error.
+///
+/// The following return codes are error codes:
+///
+/// \retval -SSX_INVALID_TIMER_AT_CANCEL The \a timer is a null (0) pointer.
+///
+/// \retval -SSX_ILLEGAL_CONTEXT_TIMER The call was made from a critical
+/// interrupt context.
+///
+
+int
+ssx_timer_cancel(SsxTimer *timer)
+{
+ SsxMachineContext ctx;
+ int rc = SSX_OK;
+
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF_CRITICAL_INTERRUPT_CONTEXT();
+ SSX_ERROR_IF(timer == 0, SSX_INVALID_TIMER_AT_CANCEL);
+ }
+
+ ssx_critical_section_enter(SSX_NONCRITICAL, &ctx);
+
+ rc = __ssx_timer_cancel(timer);
+
+ ssx_critical_section_exit(&ctx);
+
+ return rc;
+}
+
+
+/// Get information about a timer.
+///
+/// \param timer The SsxTimer to query
+///
+/// \param timeout The API returns the absolute timeout of the timer through
+/// this pointer. If the timer is active, this is the current timeout. If
+/// the timer has timed out then this is the previous absolute timeout. If
+/// the timer was never scheduled this will be 0. The caller can set this
+/// parameter to the null pointer (0) if this information is not required.
+///
+/// \param active If the value returned through this pointer is 1 then the
+/// timer is active (currently scheduled), otherwise the value will be 0
+/// indicating an inactive timer. The caller can set this parameter to the
+/// null pointer (0) if this information is not required.
+///
+/// The information returned by this API can only be guaranteed consistent if
+/// the API is called from an SSX_NONCRITICAL critical section. Since the
+/// implementation of this API does not require a critical section, it is not
+/// an error to call this API from a critical interrupt context.
+///
+/// Return values other than SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SSX_INVALID_TIMER_AT_INFO The \a timer is a null (0) pointer.
+
+int
+ssx_timer_info_get(SsxTimer *timer,
+ SsxTimebase *timeout,
+ int *active)
+
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF(timer == 0, SSX_INVALID_TIMER_AT_INFO);
+ }
+
+ if (timeout) {
+ *timeout = timer->timeout;
+ }
+ if (active) {
+ *active = timer_active(timer);
+ }
+
+ return SSX_OK;
+}
+
+#undef __SSX_TIMER_CORE_C__
diff --git a/src/ssx/ssx/ssx_timer_init.c b/src/ssx/ssx/ssx_timer_init.c
new file mode 100755
index 0000000..6c35ea6
--- /dev/null
+++ b/src/ssx/ssx/ssx_timer_init.c
@@ -0,0 +1,124 @@
+// $Id: ssx_timer_init.c,v 1.2 2014/02/03 01:30:44 daviddu Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ssx/ssx/ssx_timer_init.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ssx_timer_init.c
+/// \brief SSX timer initialization
+///
+/// The entry points in this file might only be used during initialization of
+/// the application. In this case the code space for these routines could be
+/// recovered and reused after initialization.
+
+#include "ssx.h"
+
+// Implementation of timer creation
+
+static int
+_ssx_timer_create(SsxTimer *timer,
+ SsxTimerCallback callback,
+ void *arg,
+ int options)
+{
+ if (SSX_ERROR_CHECK_API) {
+ SSX_ERROR_IF((timer == 0), SSX_INVALID_TIMER_AT_CREATE);
+ }
+
+ ssx_deque_element_create((SsxDeque*)timer);
+ timer->timeout = 0;
+ timer->period = 0;
+ timer->callback = callback;
+ timer->arg = arg;
+ timer->options = options;
+
+ return SSX_OK;
+}
+
+
+/// Create (initialize) a preemptible timer.
+///
+/// \param timer The SsxTimer to initialize.
+///
+/// \param callback The timer callback
+///
+/// \param arg Private data provided to the callback.
+///
+/// Once created with ssx_timer_create() a timer can be scheduled with
+/// ssx_timer_schedule() or ssx_timer_schedule_absolute(), which queues the
+/// timer in the kernel time queue. Timers can be cancelled by a call of
+/// ssx_timer_cancel().
+///
+/// Timers created with ssx_timer_create() are always run as noncritical
+/// interrupt handlers with interrupt preemption enabled. Timer callbacks are
+/// free to enter critical sections of any priorioty if required, but must
+/// always exit with noncritical interrupts enabled.
+///
+/// Caution: SSX has no way to know if an SsxTimer structure provided to
+/// ssx_timer_create() is safe to use as a timer, and will silently modify
+/// whatever memory is provided.
+///
+/// Return values other then SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SSX_INVALID_TIMER_AT_CREATE The \a timer is a null (0) pointer.
+
+int
+ssx_timer_create(SsxTimer *timer,
+ SsxTimerCallback callback,
+ void *arg)
+{
+ return _ssx_timer_create(timer, callback, arg,
+ SSX_TIMER_CALLBACK_PREEMPTIBLE);
+}
+
+
+/// Create (initialize) a nonpreemptible timer.
+///
+/// \param timer The SsxTimer to initialize.
+///
+/// \param callback The timer callback
+///
+/// \param arg Private data provided to the callback.
+///
+/// Once created with ssx_timer_create_preemptible() a timer can be scheduled
+/// with ssx_timer_schedule() or ssx_timer_schedule_absolute(), which queues
+/// the timer in the kernel time queue. Timers can be cancelled by a call of
+/// ssx_timer_cancel().
+///
+/// Timers created with ssx_timer_create_nonpreemptible() are always run as
+/// noncritical interrupt handlers with interrupt preemption disabled. Timer
+/// callbacks are free to later enable preemption if desired, but must always
+/// exit with noncritical interrupts disabled.
+///
+/// \note The use of ssx_timer_create_nonpreemptible() should be rare, and the
+/// timer callbacks should be short and sweet to avoid long interrupt
+/// latencies for other interrupts. This API was initially introduced for use
+/// by the SSX kernel itself when scheduling thread-timer callbacks to avoid
+/// potential race conditions with other interrupts that may modify thread
+/// state or the state of the time queue. Applications may also require this
+/// facility to guarantee a consistent state in the event that other
+/// interrupts may cancel the timer.
+///
+/// Caution: SSX has no way to know if an SsxTimer structure provided to
+/// ssx_timer_create() is safe to use as a timer, and will silently modify
+/// whatever memory is provided.
+///
+/// Return values other then SSX_OK (0) are errors; see \ref ssx_errors
+///
+/// \retval 0 Successful completion
+///
+/// \retval -SSX_INVALID_TIMER_AT_CREATE The \a timer is a null (0) pointer.
+
+int
+ssx_timer_create_nonpreemptible(SsxTimer *timer,
+ SsxTimerCallback callback,
+ void *arg)
+{
+ return _ssx_timer_create(timer, callback, arg, 0);
+}
+
+
diff --git a/src/ssx/ssx/ssxssxfiles.mk b/src/ssx/ssx/ssxssxfiles.mk
new file mode 100755
index 0000000..e78e986
--- /dev/null
+++ b/src/ssx/ssx/ssxssxfiles.mk
@@ -0,0 +1,35 @@
+# $Id: ssxssxfiles.mk,v 1.2 2014/06/26 13:02:00 cmolsen Exp $
+# $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ssx/ssx/ssxssxfiles.mk,v $
+# @file ssxpgpfiles.mk
+#
+# @brief mk for including pgp object files
+#
+# @page ChangeLogs Change Logs
+# @section ssxpgpfiles.mk
+# @verbatim
+#
+#
+# Change Log ******************************************************************
+# Flag Defect/Feature User Date Description
+# ------ -------------- ---------- ------------ -----------
+# @pb00E pbavari 03/11/2012 Makefile ODE support
+#
+# @endverbatim
+#
+##########################################################################
+# Include
+##########################################################################
+
+
+##########################################################################
+# Object Files
+##########################################################################
+SSX-C-SOURCES = ssx_core.c ssx_init.c ssx_stack_init.c
+
+SSX-TIMER-C-SOURCES += ssx_timer_core.c ssx_timer_init.c
+
+SSX-THREAD-C-SOURCES += ssx_thread_init.c ssx_thread_core.c \
+ ssx_semaphore_init.c ssx_semaphore_core.c
+
+SSX_OBJECTS += $(SSX-C-SOURCES:.c=.o)
+
OpenPOWER on IntegriCloud