summaryrefslogtreecommitdiffstats
path: root/src/lib/common
diff options
context:
space:
mode:
authorWilliam Bryan <wilbryan@us.ibm.com>2015-08-03 12:38:58 -0500
committerWilliam A. Bryan <wilbryan@us.ibm.com>2015-08-03 15:32:27 -0500
commit420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3 (patch)
treec9f6691eddba39193e39aa769367e1267fb9fc86 /src/lib/common
parentadade8c8ef30ed519322674c762d95663009c5d4 (diff)
downloadtalos-occ-420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3.tar.gz
talos-occ-420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3.zip
new ssx and lib files
Change-Id: I2328b1e86d59e3788910687d762fb70ec680058f Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/19503 Reviewed-by: William A. Bryan <wilbryan@us.ibm.com> Tested-by: William A. Bryan <wilbryan@us.ibm.com>
Diffstat (limited to 'src/lib/common')
-rw-r--r--src/lib/common/Makefile57
-rw-r--r--src/lib/common/README.txt1
-rw-r--r--src/lib/common/kernel.h363
-rw-r--r--src/lib/common/libcommonfiles.mk54
-rw-r--r--src/lib/common/memcpy.c102
-rw-r--r--src/lib/common/memset.c142
-rw-r--r--src/lib/common/rand.h124
-rw-r--r--src/lib/common/rand32.c384
-rw-r--r--src/lib/common/string.c189
-rw-r--r--src/lib/common/string.h88
-rw-r--r--src/lib/common/sync.c294
-rw-r--r--src/lib/common/sync.h167
12 files changed, 1965 insertions, 0 deletions
diff --git a/src/lib/common/Makefile b/src/lib/common/Makefile
new file mode 100644
index 0000000..5147b59
--- /dev/null
+++ b/src/lib/common/Makefile
@@ -0,0 +1,57 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/lib/common/Makefile $
+#
+# OpenPOWER OnChipController Project
+#
+# Contributors Listed Below - COPYRIGHT 2015
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+# IBM_PROLOG_END_TAG
+# This Makefile currently builds a single archive, 'libcommon.a', from
+# various library source files.
+#
+# part of the complete application build.
+#
+
+#all generated files from this makefile will end up in obj/$(IMAGE_NAME)/common
+export SUB_OBJDIR = /commonlib
+
+include img_defs.mk
+include libcommonfiles.mk
+
+OBJS := $(addprefix $(OBJDIR)/, $(LIBCOMMON_OBJECTS))
+
+libcommon.a: local
+ $(AR) crs $(OBJDIR)/libcommon.a $(OBJDIR)/*.o
+
+.PHONY: clean
+
+local: $(OBJS)
+
+$(OBJS) $(OBJS:.o=.d): | $(OBJDIR)
+
+$(OBJDIR):
+ mkdir -p $(OBJDIR)
+
+clean:
+ rm -fr $(OBJDIR)
+
+ifneq ($(MAKECMDGOALS),clean)
+#include $(OBJS:.o=.d)
+endif
+
diff --git a/src/lib/common/README.txt b/src/lib/common/README.txt
new file mode 100644
index 0000000..760da25
--- /dev/null
+++ b/src/lib/common/README.txt
@@ -0,0 +1 @@
+This directory contains code that can run on any PPE or 405 processor.
diff --git a/src/lib/common/kernel.h b/src/lib/common/kernel.h
new file mode 100644
index 0000000..063d35c
--- /dev/null
+++ b/src/lib/common/kernel.h
@@ -0,0 +1,363 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/common/kernel.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __KERNEL_H__
+#define __KERNEL_H__
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file kernel.h
+/// \brief Kernel agnostic macros that allow the same code to work with
+/// different kernels.
+///
+/// Programmers can include this instead of pk.h or ssx.h
+///
+///
+#ifndef __ASSEMBLER__
+#ifdef __SSX__
+
+/// ----------------------- Use SSX kernel interfaces --------------------------
+
+#include "ssx.h"
+
+//Types
+#define KERN_SEMAPHORE SsxSemaphore
+#define KERN_SEMAPHORE_COUNT SsxSemaphoreCount
+#define KERN_DEQUE SsxDeque
+#define KERN_THREAD SsxThread
+#define KERN_THREAD_PRIORITY SsxThreadPriority
+#define KERN_THREAD_STATE SsxThreadState
+#define KERN_THREAD_ROUTINE SsxThreadRoutine
+#define KERN_THREAD_FLAGS SsxThreadFlags
+#define KERN_ADDRESS SsxAddress
+#define KERN_TIMER SsxTimer
+#define KERN_TIMER_CALLBACK SsxTimerCallback
+#define KERN_INTERVAL SsxInterval
+#define KERN_TIMEBASE SsxTimebase
+#define KERN_IRQ_ID SsxIrqId
+#define KERN_MACHINE_CONTEXT SsxMachineContext
+
+//Constants
+#define KERN_SEMAPHORE_PEND_TIMED_OUT SSX_SEMAPHORE_PEND_TIMED_OUT
+#define KERN_SEMAPHORE_PEND_NO_WAIT SSX_SEMAPHORE_PEND_NO_WAIT
+#define KERN_NONCRITICAL SSX_NONCRITICAL
+#define KERN_CRITICAL SSX_CRITICAL
+#define KERN_SUPERCRITICAL SSX_SUPERCRITICAL
+#define KERN_ERROR_CHECK_API SSX_ERROR_CHECK_API
+#define KERN_NO_WAIT SSX_NO_WAIT
+#define KERN_WAIT_FOREVER SSX_WAIT_FOREVER
+
+//Functions
+#define KERN_SECONDS(s) SSX_SECONDS(s)
+#define KERN_MILLISECONDS(m) SSX_MILLISECONDS(m)
+#define KERN_MICROSECONDS(u) SSX_MICROSECONDS(u)
+#define KERN_NANOSECONDS(n) SSX_NANOSECONDS(n)
+
+#define KERN_TIMEBASE_GET() ssx_timebase_get()
+#define KERN_TIMEBASE_SET(tb) ssx_timebase_set(tb)
+
+#define KERN_INTERRUPT_PREEMPTION_ENABLE() ssx_interrupt_preemption_enable()
+#define KERN_INTERRUPT_PREEMPTION_DISABLE() ssx_interrupt_preemption_disable()
+
+#define KERN_TIMER_CREATE(timer, callback, arg) \
+ ssx_timer_create(timer, callback, arg)
+#define KERN_TIMER_CREATE_NONPREEMPTIBLE(timer, callback, arg) \
+ ssx_timer_create_nonpreemptible(timer, callback, arg)
+#define KERN_TIMER_SCHEDULE_ABSOLUTE(timer, time, period) \
+ ssx_timer_schedule_absolute(timer, time, period)
+#define KERN_TIMER_SCHEDULE(timer, interval, period) \
+ ssx_timer_schedule(timer, interval, period)
+#define KERN_TIMER_CANCEL(timer) \
+ ssx_timer_cancel(timer)
+#define KERN_TIMER_INFO_GET(timer, timeout, active) \
+ ssx_timer_info_get(timer, timeout, active)
+
+#define KERN_THREAD_CREATE(thread, thread_routine, arg, stack, stack_size, priority) \
+ ssx_thread_create(thread, thread_routine, arg, stack, stack_size, priority)
+#define KERN_THREAD_INFO_GET(thread, state, priority, runnable) \
+ ssx_thread_info_get(thread, state, priority, runnable)
+#define KERN_THREAD_PRIORTY_CHANGE(thread, new_priority, old_priority) \
+ ssx_thread_priority_change(thread, new_priority, old_priority)
+#define KERN_THREAD_AT_PRIORITY(priority, thread) \
+ ssx_thread_at_priority(priority, thread)
+#define KERN_THREAD_PRIORITY_SWAP(thread_a, thread_b) \
+ ssx_thread_priority_swap(thread_a, thread_b)
+
+#define KERN_START_THREADS() ssx_start_threads()
+#define KERN_THREAD_RESUME(thread) ssx_thread_resume(thread)
+#define KERN_THREAD_SUSPEND(thread) ssx_thread_suspend(thread)
+#define KERN_THREAD_DELETE(thread) ssx_thread_delete(thread)
+#define KERN_COMPLETE() ssx_complete()
+#define KERN_SLEEP_ABSOLUTE(time) ssx_sleep_absolute(time)
+#define KERN_SLEEP(interval) ssx_sleep(interval)
+
+#define KERN_SEMAPHORE_CREATE(semaphore, initial_count, max_count) \
+ ssx_semaphore_create(semaphore, initial_count,max_count)
+#define KERN_SEMAPHORE_STATIC_CREATE(sem, initial_count, max_count) \
+ SSX_SEMAPHORE(sem, initial_count, max_count)
+#define KERN_SEMAPHORE_INITIALIZATION(_initial_count, _max_count) \
+ SSX_SEMAPHORE_INITIALIZATION(_initial_count, _max_count)
+#define KERN_SEMAPHORE_INFO_GET(semaphore, count, pending) \
+ ssx_semaphore_info_get(semaphore, count, pending)
+
+#define KERN_SEMAPHORE_POST(semaphore) \
+ ssx_semaphore_post(semaphore)
+#define KERN_SEMAPHORE_PEND(semaphore, timeout) \
+ ssx_semaphore_pend(semaphore, timeout)
+#define KERN_SEMAPHORE_RELEASE_ALL(semaphore) \
+ ssx_semaphore_release_all(semaphore)
+#define KERN_SEMAPHORE_POST_HANDLER(arg, irq, priority) \
+ ssx_semaphore_post_handler(arg, irq, priority)
+
+
+#define KERN_HALT() \
+ ssx_halt()
+#define KERN_PANIC(code) \
+ SSX_PANIC(code)
+
+#define KERN_DEQUE_SENTINEL_CREATE(deque) \
+ ssx_deque_sentinel_create(deque)
+#define KERN_DEQUE_SENTINEL_STATIC_CREATE(deque) \
+ SSX_DEQUE_SENTINEL_STATIC_CREATE(deque)
+#define KERN_DEQUE_SENTINEL_INIT(dq_addr) \
+ SSX_DEQUE_SENTINEL_INIT(dq_addr)
+#define KERN_DEQUE_ELEMENT_CREATE(element) \
+ ssx_deque_element_create(element)
+#define KERN_DEQUE_ELEMENT_STATIC_CREATE(deque) \
+ SSX_DEQUE_ELEMENT_STATIC_CREATE(deque)
+#define KERN_DEQUE_ELEMENT_INIT() \
+ SSX_DEQUE_ELEMENT_INIT()
+#define KERN_DEQUE_IS_EMPTY(deque) \
+ ssx_deque_is_empty(deque)
+#define KERN_DEQUE_IS_QUEUED(element) \
+ ssx_deque_is_queued(element)
+#define KERN_DEQUE_PUSH_BACK(deque, element) \
+ ssx_deque_push_back(deque, element)
+#define KERN_DEQUE_PUSH_FRONT(deque, element) \
+ ssx_deque_push_front(deque, element)
+#define KERN_DEQUE_POP_FRONT(deque) \
+ ssx_deque_pop_front(deque)
+#define KERN_DEQUE_DELETE(element) \
+ ssx_deque_delete(element)
+
+#define KERN_IRQ_HANDLER(f) \
+ SSX_IRQ_HANDLER(f)
+#define KERN_IRQ_SETUP(irq, polarity, trigger) \
+ ssx_irq_setup(irq, polarity, trigger)
+#define KERN_IRQ_HANDLER_SET(irq, handler, arg, priority) \
+ ssx_irq_handler_set(irq, handler, arg, priority)
+#define KERN_IRQ_ENABLE(irq) \
+ ssx_irq_enable(irq)
+#define KERN_IRQ_DISABLE(irq) \
+ ssx_irq_disable(irq)
+#define KERN_IRQ_STATUS_CLEAR(irq) \
+ ssx_irq_status_clear(irq)
+#define KERN_IRQ_STATUS_SET(irq, value) \
+ ssx_irq_status_set(irq, value)
+#define KERN_IRQ_FAST2FULL(fast_handler, full_handler) \
+ SSX_IRQ_FAST2FULL(fast_handler, full_handler)
+
+#define KERN_CRITICAL_SECTION_ENTER(priority, pctx) \
+ ssx_critical_section_enter(priority, pctx)
+#define KERN_CRITICAL_SECTION_EXIT(pctx) \
+ ssx_critical_section_exit(pctx)
+#define KERN_CONTEXT_CRITICAL_INTERRUPT() \
+ __ssx_kernel_context_critical_interrupt()
+
+#define KERN_ERROR_IF(condition, code) SSX_ERROR_IF(condition, code)
+
+#define KERN_CAST_POINTER(t, p) SSX_CAST_POINTER(t, p)
+
+#define KERN_STATIC_ASSERT(cond) SSX_STATIC_ASSERT(cond)
+
+#elif defined(__PK__)
+
+/// ----------------------- Use PK kernel interfaces --------------------------
+
+#include "pk.h"
+
+//Types
+#define KERN_SEMAPHORE PkSemaphore
+#define KERN_SEMAPHORE_COUNT PkSemaphoreCount
+#define KERN_DEQUE PkDeque
+#define KERN_THREAD PkThread
+#define KERN_THREAD_PRIORITY PkThreadPriority
+#define KERN_THREAD_STATE PkThreadState
+#define KERN_THREAD_ROUTINE PkThreadRoutine
+#define KERN_THREAD_FLAGS PkThreadFlags
+#define KERN_ADDRESS PkAddress
+#define KERN_TIMER PkTimer
+#define KERN_TIMER_CALLBACK PkTimerCallback
+#define KERN_INTERVAL PkInterval
+#define KERN_TIMEBASE PkTimebase
+#define KERN_IRQ_ID PkIrqId
+#define KERN_MACHINE_CONTEXT PkMachineContext
+
+//Constants
+#define KERN_SEMAPHORE_PEND_TIMED_OUT PK_SEMAPHORE_PEND_TIMED_OUT
+#define KERN_SEMAPHORE_PEND_NO_WAIT PK_SEMAPHORE_PEND_NO_WAIT
+#define KERN_NONCRITICAL 0
+#define KERN_CRITICAL 0
+#define KERN_SUPERCRITICAL 0
+#define KERN_ERROR_CHECK_API PK_ERROR_CHECK_API
+#define KERN_NO_WAIT PK_NO_WAIT
+#define KERN_WAIT_FOREVER PK_WAIT_FOREVER
+
+//Functions
+#define KERN_SECONDS(s) PK_SECONDS(s)
+#define KERN_MILLISECONDS(m) PK_MILLISECONDS(m)
+#define KERN_MICROSECONDS(u) PK_MICROSECONDS(u)
+#define KERN_NANOSECONDS(n) PK_NANOSECONDS(n)
+
+#define KERN_TIMEBASE_GET() pk_timebase_get()
+#define KERN_TIMEBASE_SET(tb) pk_timebase_set(tb)
+
+#define KERN_INTERRUPT_PREEMPTION_ENABLE() pk_interrupt_preemption_enable()
+#define KERN_INTERRUPT_PREEMPTION_DISABLE() pk_interrupt_preemption_disable()
+
+#define KERN_TIMER_CREATE(timer, callback, arg) \
+ pk_timer_create(timer, callback, arg)
+#define KERN_TIMER_CREATE_NONPREEMPTIBLE(timer, callback, arg) \
+ pk_timer_create_nonpreemptible(timer, callback, arg)
+#define KERN_TIMER_SCHEDULE_ABSOLUTE(timer, time, period) \
+ pk_timer_schedule_absolute(timer, time, period)
+#define KERN_TIMER_SCHEDULE(timer, interval, period) \
+ pk_timer_schedule(timer, interval, period)
+#define KERN_TIMER_CANCEL(timer) \
+ pk_timer_cancel(timer)
+#define KERN_TIMER_INFO_GET(timer, timeout, active) \
+ pk_timer_info_get(timer, timeout, active)
+
+#define KERN_THREAD_CREATE(thread, thread_routine, arg, stack, stack_size, priority) \
+ pk_thread_create(thread, thread_routine, arg, stack, stack_size, priority)
+#define KERN_THREAD_INFO_GET(thread, state, priority, runnable) \
+ pk_thread_info_get(thread, state, priority, runnable)
+#define KERN_THREAD_PRIORTY_CHANGE(thread, new_priority, old_priority) \
+ pk_thread_priority_change(thread, new_priority, old_priority)
+#define KERN_THREAD_AT_PRIORITY(priority, thread) \
+ pk_thread_at_priority(priority, thread)
+#define KERN_THREAD_PRIORITY_SWAP(thread_a, thread_b) \
+ pk_thread_priority_swap(thread_a, thread_b)
+
+#define KERN_START_THREADS() pk_start_threads()
+#define KERN_THREAD_RESUME(thread) pk_thread_resume(thread)
+#define KERN_THREAD_SUSPEND(thread) pk_thread_suspend(thread)
+#define KERN_THREAD_DELETE(thread) pk_thread_delete(thread)
+#define KERN_COMPLETE() pk_complete()
+#define KERN_SLEEP_ABSOLUTE(time) pk_sleep_absolute(time)
+#define KERN_SLEEP(interval) pk_sleep(interval)
+
+#define KERN_SEMAPHORE_CREATE(semaphore, initial_count, max_count) \
+ pk_semaphore_create(semaphore, initial_count,max_count)
+#define KERN_SEMAPHORE_STATIC_CREATE(sem, initial_count, max_count) \
+ PK_SEMAPHORE(sem, initial_count, max_count)
+#define KERN_SEMAPHORE_INITIALIZATION(_initial_count, _max_count) \
+ PK_SEMAPHORE_INITIALIZATION(_initial_count, _max_count)
+#define KERN_SEMAPHORE_INFO_GET(semaphore, count, pending) \
+ pk_semaphore_info_get(semaphore, count, pending)
+
+#define KERN_SEMAPHORE_POST(semaphore) \
+ pk_semaphore_post(semaphore)
+#define KERN_SEMAPHORE_PEND(semaphore, timeout) \
+ pk_semaphore_pend(semaphore, timeout)
+#define KERN_SEMAPHORE_RELEASE_ALL(semaphore) \
+ pk_semaphore_release_all(semaphore)
+#define KERN_SEMAPHORE_POST_HANDLER(arg, irq, priority) \
+ pk_semaphore_post_handler(arg, irq, priority)
+
+
+#define KERN_HALT() \
+ pk_halt()
+#define KERN_PANIC(code) \
+ PK_PANIC(code)
+
+#define KERN_DEQUE_SENTINEL_CREATE(deque) \
+ pk_deque_sentinel_create(deque)
+#define KERN_DEQUE_SENTINEL_STATIC_CREATE(deque) \
+ PK_DEQUE_SENTINEL_STATIC_CREATE(deque)
+#define KERN_DEQUE_SENTINEL_INIT(dq_addr) \
+ PK_DEQUE_SENTINEL_INIT(dq_addr)
+#define KERN_DEQUE_ELEMENT_CREATE(element) \
+ pk_deque_element_create(element)
+#define KERN_DEQUE_ELEMENT_STATIC_CREATE(deque) \
+ PK_DEQUE_ELEMENT_STATIC_CREATE(deque)
+#define KERN_DEQUE_ELEMENT_INIT() \
+ PK_DEQUE_ELEMENT_INIT()
+#define KERN_DEQUE_IS_EMPTY(deque) \
+ pk_deque_is_empty(deque)
+#define KERN_DEQUE_IS_QUEUED(element) \
+ pk_deque_is_queued(element)
+#define KERN_DEQUE_PUSH_BACK(deque, element) \
+ pk_deque_push_back(deque, element)
+#define KERN_DEQUE_PUSH_FRONT(deque, element) \
+ pk_deque_push_front(deque, element)
+#define KERN_DEQUE_POP_FRONT(deque) \
+ pk_deque_pop_front(deque)
+#define KERN_DEQUE_DELETE(element) \
+ pk_deque_delete(element)
+
+#define KERN_IRQ_HANDLER(f) \
+ PK_IRQ_HANDLER(f)
+#define KERN_IRQ_SETUP(irq, polarity, trigger) \
+ pk_irq_setup(irq, polarity, trigger)
+#define KERN_IRQ_HANDLER_SET(irq, handler, arg, priority) \
+ pk_irq_handler_set(irq, handler, arg)
+#define KERN_IRQ_ENABLE(irq) \
+ pk_irq_enable(irq)
+#define KERN_IRQ_DISABLE(irq) \
+ pk_irq_disable(irq)
+#define KERN_IRQ_STATUS_CLEAR(irq) \
+ pk_irq_status_clear(irq)
+#define KERN_IRQ_STATUS_SET(irq, value) \
+ pk_irq_status_set(irq, value)
+#define KERN_IRQ_FAST2FULL(fast_handler, full_handler) \
+ PK_IRQ_FAST2FULL(fast_handler, full_handler)
+
+#define KERN_CRITICAL_SECTION_ENTER(priority, pctx) \
+ pk_critical_section_enter(pctx)
+#define KERN_CRITICAL_SECTION_EXIT(pctx) \
+ pk_critical_section_exit(pctx)
+#define KERN_CONTEXT_CRITICAL_INTERRUPT() \
+ (0)
+
+#define KERN_ERROR_IF(condition, code) PK_ERROR_IF(condition, code)
+
+#define KERN_CAST_POINTER(t, p) PK_CAST_POINTER(t, p)
+
+#define KERN_STATIC_ASSERT(cond) PK_STATIC_ASSERT(cond)
+
+#else
+
+/// ----------------------- Kernel type not defined --------------------------
+
+#error "Kernel type must be defined in img_defs.mk"
+
+#endif /*__SSX__*/
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* __KERNEL_H__ */
diff --git a/src/lib/common/libcommonfiles.mk b/src/lib/common/libcommonfiles.mk
new file mode 100644
index 0000000..9fe7592
--- /dev/null
+++ b/src/lib/common/libcommonfiles.mk
@@ -0,0 +1,54 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/lib/common/libcommonfiles.mk $
+#
+# OpenPOWER OnChipController Project
+#
+# Contributors Listed Below - COPYRIGHT 2015
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+# IBM_PROLOG_END_TAG
+# @file libcommonfiles.mk
+#
+# @brief mk for libcommon.a object files
+#
+# @page ChangeLogs Change Logs
+# @section ofiles.mk
+# @verbatim
+#
+#
+# Change Log ******************************************************************
+# Flag Defect/Feature User Date Description
+# ------ -------------- ---------- ------------ -----------
+#
+# @endverbatim
+#
+##########################################################################
+# INCLUDES
+##########################################################################
+
+C-SOURCES = \
+ memcpy.c \
+ memset.c \
+ rand32.c \
+ string.c \
+ sync.c
+
+
+S-SOURCES =
+
+LIBCOMMON_OBJECTS = $(C-SOURCES:.c=.o) $(S-SOURCES:.S=.o)
diff --git a/src/lib/common/memcpy.c b/src/lib/common/memcpy.c
new file mode 100644
index 0000000..77827dc
--- /dev/null
+++ b/src/lib/common/memcpy.c
@@ -0,0 +1,102 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/common/memcpy.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: memcpy.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/memcpy.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file memcpy.c
+/// \brief The memcpy() function
+
+#include "kernel.h"
+
+/// The memcpy() function copies \a n bytes from memory area \a src to memory
+/// area \a dest. The memory areas should not overlap. Use memmove(3) if the
+/// memory areas do overlap. The memcpy() function returns a pointer to dest.
+
+// This implementation should work well for both 32-bit and 64-bit machines,
+// assuming they can handle unaligned accesses. The implementation assumes that
+// it is better to avoid the loop setup overhead by a test and branch for
+// cases where loops can be bypassed.
+
+//void *
+//memcpy(void *dest, const void *src, size_t n)
+//{
+// while(n--) {
+// *dest++ = *src++;
+// }
+//
+// return s;
+//}
+
+void *
+memcpy(void *dest, const void *src, size_t n)
+{
+ uint8_t *d8, *s8;
+ uint64_t *d64, *s64;
+ size_t doublewords, octawords;
+
+ // First copy memory 32 bytes at a time.
+
+ d64 = (uint64_t *)dest;
+ s64 = (uint64_t *)src;
+ octawords = n / 32;
+ if (octawords) {
+ n -= octawords * 32;
+ while(octawords--) {
+ *d64++ = *s64++;
+ *d64++ = *s64++;
+ *d64++ = *s64++;
+ *d64++ = *s64++;
+ }
+ }
+
+ // Now set memory 8 bytes at a time. This might actually be better done
+ // explicitly rather than as a loop because the maximum loop count is 3
+ // here.
+
+ doublewords = n / 8;
+ if (doublewords) {
+ n -= doublewords * 8;
+ while (doublewords--) {
+ *d64++ = *s64++;
+ }
+ }
+
+ // Finally finish any remaining memory bytewise
+
+ if (n) {
+ d8 = (uint8_t *)d64;
+ s8 = (uint8_t *)s64;
+ while (n--) {
+ *d8++ = *s8++;
+ }
+ }
+
+ return dest;
+}
diff --git a/src/lib/common/memset.c b/src/lib/common/memset.c
new file mode 100644
index 0000000..1d98677
--- /dev/null
+++ b/src/lib/common/memset.c
@@ -0,0 +1,142 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/common/memset.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: memset.c,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/memset.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file memset.c
+/// \brief The memset() function
+
+#include "kernel.h"
+
+/// The memset() function fills the first \a n bytes of the memory area
+/// pointed to by \a s with the constant byte \a c. The memset() function
+/// returns a pointer to the memory area \a s.
+///
+/// Note that memset() is optimized for setting large memory areas, and
+/// entails quite a bit of overhead to do this efficiently. If a memory area
+/// consists of a small number of basic data types (e.g., integers) it is
+/// probably more time-efficient to set the memory directly with a for loop
+/// (or unrolled loop).
+
+// This implementation should work well for both 32-bit and 64-bit
+// machines. The implementation assumes that it is worthwhile to align memory
+// pointers and do as much as possible using aligned addresses. [This doesn't
+// seem to matter on an X86 server processor, however]. It also assumes that
+// it is better to avoid the loop setup overhead by a test and branch for
+// cases where loops can be bypassed.
+
+//void *
+//memset(void *s, int c, size_t n)
+//{
+// uint8_t byte = (uint8_t)c;
+// uint8_t *p = (uint8_t *)s;
+//
+// while(n--) {
+// *p++ = byte;
+// }
+//
+// return s;
+//}
+
+void *
+memset(void *s, int c, size_t n)
+{
+ uint8_t byte, *p8;
+ uint32_t word;
+ uint64_t doubleword, *p64;
+ size_t bytes, doublewords, octawords;
+
+ // Any initial memory segment not aligned to an 8-byte boundary is set
+ // bytewise.
+
+ byte = (uint8_t)c;
+ p8 = (uint8_t *)s;
+
+ bytes = MIN(n, (unsigned long)s % 8);
+ if (bytes) {
+ n -= bytes;
+ while (bytes--) {
+ *p8++ = byte;
+ }
+ }
+
+ // Short requests are finshed here as well.
+
+ if (n < 8) {
+ while (n--) {
+ *p8++ = byte;
+ }
+ return s;
+ }
+
+ // We have at least 8 bytes of memory aligned on an 8-byte boundary. A
+ // doubleword initializer is created.
+
+ word = (byte << 8) | byte;
+ word = (word << 16) | word;
+ doubleword = ((uint64_t)word << 32) | word;
+
+ // First set memory 32 bytes at a time.
+
+ p64 = (uint64_t *)p8;
+ octawords = n / 32;
+ if (octawords) {
+ n -= octawords * 32;
+ while(octawords--) {
+ *p64++ = doubleword;
+ *p64++ = doubleword;
+ *p64++ = doubleword;
+ *p64++ = doubleword;
+ }
+ }
+
+ // Now set memory 8 bytes at a time. This might actually be better done
+ // explicitly rather than as a loop because the maximum loop count is 3
+ // here.
+
+ doublewords = n / 8;
+ if (doublewords) {
+ n -= doublewords * 8;
+ while (doublewords--) {
+ *p64++ = doubleword;
+ }
+ }
+
+ // Finally finish any remaining memory bytewise
+
+ p8 = (uint8_t *)p64;
+ if (n) {
+ while (n--) {
+ *p8++ = byte;
+ }
+ }
+
+ return s;
+}
diff --git a/src/lib/common/rand.h b/src/lib/common/rand.h
new file mode 100644
index 0000000..369b8fd
--- /dev/null
+++ b/src/lib/common/rand.h
@@ -0,0 +1,124 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/common/rand.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __RAND_H__
+#define __RAND_H__
+
+// $Id$
+
+/// \file rand.h
+/// \brief Random number generation
+
+#include <stdint.h>
+
+// Error/Panic codes
+
+#define RAND64_UNIMPLEMENTED 0x00726301
+
+
+/// RAND32_ALL is used as the \a limit argument to rand32() and _rand32() to
+/// request the return of a full 32-bit random unsigned integer.
+
+#define RAND32_ALL 0
+
+extern uint32_t _seed32;
+
+uint32_t
+_rand32(uint32_t *seed, uint32_t limit);
+
+uint32_t
+rand32(uint32_t limit);
+
+void
+srand32(uint32_t seed);
+
+
+/// RAND64_ALL is used as the \a limit argument to rand64() and _rand64() to
+/// request the return of a full 64-bit random unsigned integer.
+
+#define RAND64_ALL 0
+
+extern uint64_t _seed64;
+
+//void
+//davidmult64to128(uint64_t u, uint64_t v, uint64_t &h, uint64_t &l);
+
+uint64_t
+_rand64(uint64_t *seed, uint64_t limit);
+
+uint64_t
+rand64(uint64_t limit);
+
+void
+srand64(uint64_t seed);
+
+
+/// A random weighting map for integer selections
+///
+/// See rand_map_int() for details.
+
+typedef struct {
+
+ /// The relative weight of this selection
+ ///
+ /// The final weight of the map array \e must be 0 to terminate the map.
+ unsigned weight;
+
+ /// The selection
+ int selection;
+
+} RandMapInt;
+
+
+/// A random weighting map for pointer selections
+///
+/// See rand_map_ptr() for details.
+
+typedef struct {
+
+ /// The relative weight of this selection
+ ///
+ /// The final weight of the map array \e must be 0 to terminate the map.
+ unsigned weight;
+
+ /// The selection
+ void *selection;
+
+} RandMapPtr;
+
+
+int
+_rand_map_int(uint32_t *seed, RandMapInt *map, int *index);
+
+int
+rand_map_int(RandMapInt *map);
+
+void *
+_rand_map_ptr(uint32_t *seed, RandMapPtr *map, int *index);
+
+void *
+rand_map_ptr(RandMapPtr *map);
+
+
+#endif /* __RAND_H__ */
diff --git a/src/lib/common/rand32.c b/src/lib/common/rand32.c
new file mode 100644
index 0000000..c75fc76
--- /dev/null
+++ b/src/lib/common/rand32.c
@@ -0,0 +1,384 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/common/rand32.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id$
+
+/// \file rand32.c
+/// \brief 32-bit unsigned pseudo-random number generation
+
+#include "rand.h"
+
+/// The default seed for rand32()
+
+uint32_t _seed32 = 405405405;
+
+
+/// Generate a random 32-bit unsigned integer from an explicit seed
+///
+/// \param seed A pointer to the random seed (updated by this routine).
+///
+/// \param limit The (exclusive) upper bound of the range of generated random
+/// integers. The (inclusive) lower bound is always 0.
+///
+/// \retval A pseudo-random unsigned 32-bit integer uniformly selected from
+/// the range 0 to \a limit - 1 (inclusive). However if the \a limit parameter
+/// is \c RAND32_ALL (0), then the return value is a full 32-bit random bit
+/// vector.
+///
+/// This is a 32-bit linear congruential generator, taken from the 'ranqd1'
+/// generator from "Numerical Recipes in C". The authors' only praise for
+/// this generator is that it is "\e very fast"; the quality of random numbers
+/// is deemed "entirely adequate for many uses".
+///
+/// The initial 32 pseudo-random result is treated as a 32-bit binary fraction
+/// that is multipled by the limit to yield the final random 32-bit
+/// integer. If the limit is 0, then the full 32-bit result is returned. As
+/// with all LCG, do not count on the low-order bits to be particularly
+/// random.
+
+uint32_t
+_rand32(uint32_t *seed, uint32_t limit)
+{
+ uint64_t x;
+
+ *seed = (*seed * 1664525) + 1013904223;
+ if (limit == RAND32_ALL) {
+ return *seed;
+ } else {
+ x = (uint64_t)(*seed) * limit;
+ return x >> 32;
+ }
+}
+
+
+/// Generate a random 32-bit unsigned integer from a system-wide seed
+///
+/// \param limit The (exclusive) upper bound of the range of generated random
+/// integers. The (inclusive) lower bound is always 0.
+///
+/// \retval A pseudo-random unsigned 32-bit integer uniformly selected from
+/// the range 0 to \a limit - 1 (inclusive). However if the \a limit parameter
+/// is \c RAND32_ALL (0), then the return value is a full 32-bit random bit
+/// vector.
+///
+/// rand32() is not thread safe. There is a small possibility that multiple
+/// threads may observe the same random numbers, and it is also possible that
+/// the random sequence may appear to repeat due to thread interactions. If
+/// these are concerns then the application should either call rand32() from
+/// within a critical section, or provide a unique seed to each thread or
+/// process and use the underlying _rand32() API explicitly.
+
+uint32_t
+rand32(uint32_t limit)
+{
+ return _rand32(&_seed32, limit);
+}
+
+
+/// Set the global random seed for rand32()
+
+void
+srand32(uint32_t seed)
+{
+ _seed32 = seed;
+}
+
+
+/// Select an integer from a weighted distribution using a specific seed
+///
+/// \param seed A 32-bit unsigned random seed (accumulator)
+///
+/// \param map An array of RandMapInt structures, the final element of which
+/// must have the \a weight field = 0. This array will typically be allocated
+/// statically.
+///
+/// \param index An optional pointer to an integer which will recieve the
+/// index of the item selected. NULL \a index are ignored. This is provided
+/// for appplications that require statistics on selections.
+///
+/// \retval One of the \a selection from the array with a non-0 \a weight. If
+/// the weight array is NULL (= {{0, \<dont care\>}}), then by convention the
+/// return value is 0, and the return index is -1.
+///
+/// This routine selects items from the \a map randomly, given the weighting
+/// implied by (map[i].weight / SUM(i = 0,...,N, map[i].weight)). For
+/// example, the following two maps are equivalent in that they select 'a' and
+/// 'c' with 25% probability, and 'b' with 50% probability:
+///
+/// RandMapInt map0[] = {{1, 'a'}, {2, 'b'}, {1, 'c'}, {0, 0}};
+///
+/// RandMapInt map1[] = {{25, 'a'}, {50, 'b'}, {25, 'c'}, {0, 0}};
+///
+/// Note that several errors including negative weights, or the overflow of
+/// the sum of weights as an \a unsigned number are neither detected nor
+/// reported.
+///
+/// \todo We could probably merge the code for the integer and pointer versions
+/// somewhat. This is a great example of where C++ would be nice, as we could
+/// easily cache the sum of weights when the map was constructed.
+
+int
+_rand_map_int(uint32_t *seed, RandMapInt *map, int *index)
+{
+ unsigned weight, sum;
+ RandMapInt *p;
+ uint32_t rand;
+ int i = -1;
+ int selection = 0;
+
+ sum = 0;
+ p = map;
+ while (p->weight != 0) {
+ sum += p->weight;
+ p++;
+ }
+
+ if (sum != 0) {
+
+ rand = _rand32(seed, sum);
+
+ weight = 0;
+ p = map;
+ i = 0;
+ while (p->weight != 0) {
+ weight += p->weight;
+ if (rand < weight) {
+ selection = p->selection;
+ break;
+ }
+ p++;
+ i++;
+ }
+ }
+
+ if (index != 0) {
+ *index = i;
+ }
+
+ return selection;
+}
+
+
+/// Select an integer from a weighted distribution using the system-side seed
+/// \a _seed32
+///
+/// See _rand_map_int() for documentation
+
+int
+rand_map_int(RandMapInt *map)
+{
+ return _rand_map_int(&_seed32, map, 0);
+}
+
+
+/// Select a pointer from a weighted distribution using a specific seed
+///
+/// \param seed A 32-bit unsigned random seed (accumulator)
+///
+/// \param map An array of RandMapPtr structures, the final element of which
+/// must have the \a weight field = 0. This array will typically be allocated
+/// statically.
+///
+/// \param index An optional pointer to an integer which will recieve the
+/// index of the item selected. NULL \a index are ignored. This is provided
+/// for appplications that require statistics on selections.
+///
+/// \retval One of the \a selection from the array with a non-0 \a weight. If
+/// the weight array is NULL (= {{0, \<dont care\>}}), then by convention the
+/// return value is 0, and the return index is -1;
+///
+/// This routine selects items from the \a map randomly, given the weighting
+/// implied by (map[i].weight / SUM(i = 0,...,N, map[i].weight)). For
+/// example, the following two maps are equivalent in that they select &a and
+/// &c with 25% probability, and &b with 50% probability:
+///
+/// RandMapPtr map0[] = {{1, &a}, {2, &b}, {1, &c}, {0, 0}};
+///
+/// RandMapPtr map1[] = {{25, &a}, {50, &b}, {25, &c}, {0, 0}};
+///
+/// Note that several errors including negative weights, or the overflow of
+/// the sum of weights as an \a unsigned number are neither detected nor
+/// reported.
+
+
+void *
+_rand_map_ptr(uint32_t *seed, RandMapPtr *map, int *index)
+{
+ unsigned weight, sum;
+ RandMapPtr *p;
+ uint32_t rand;
+ int i = -1;
+ void *selection = 0;
+
+ sum = 0;
+ p = map;
+ while (p->weight != 0) {
+ sum += p->weight;
+ p++;
+ }
+
+ if (sum != 0) {
+
+ rand = _rand32(seed, sum);
+
+ weight = 0;
+ p = map;
+ i = 0;
+ while (p->weight != 0) {
+ weight += p->weight;
+ if (rand < weight) {
+ selection = p->selection;
+ break;
+ }
+ p++;
+ i++;
+ }
+ }
+
+ if (index != 0) {
+ *index = i;
+ }
+
+ return selection;
+}
+
+
+/// Select a pointer from a weighted distribution using the system-side seed
+/// \a _seed32
+///
+/// See _rand_map_ptr() for documentation
+
+void *
+rand_map_ptr(RandMapPtr *map)
+{
+ return _rand_map_ptr(&_seed32, map, 0);
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+
+#ifdef __TEST_RAND_C__
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef RANDOM_MAP
+
+// Weighted distribution testing
+
+int a, b, c;
+int aa, bb, cc;
+
+int x[3];
+
+RandMapPtr map0[] = {{1, &a}, {2, &b}, {1, &c}, {0, 0}};
+RandMapPtr map1[] = {{25, &aa}, {50, &bb}, {25, &cc}, {0, 0}};
+
+RandMapInt map2[] = {{25, 0}, {50, 1}, {25, 2}, {0, 0}};
+
+int
+main()
+{
+ int i, j;
+ int *p;
+
+ for (i = 0; i < 1000000; i++) {
+ p = (int *)(rand_map_ptr(map0));
+ *p = *p + 1;
+ p = (int *)(rand_map_ptr(map1));
+ *p = *p + 1;
+ j = rand_map_int(map2);
+ x[j]++;
+ }
+
+ printf("%d %d %d\n", a, b, c);
+ printf("%d %d %d\n", aa, bb, cc);
+ printf("%d %d %d\n", x[0], x[1], x[2]);
+
+ return 0;
+}
+
+#endif /* RANDOM_MAP */
+
+
+#ifdef BASIC_TEST
+
+// Simple self-checking uniform distrubution tests for rand32.
+
+void
+test(int *a, int size, int count, double max_error)
+{
+ int i;
+ double error;
+
+ for (i = 0; i < size; i++) {
+ a[i] = 0;
+ }
+
+ for (i = 0; i < size * count; i++) {
+ a[rand32(size)]++;
+ }
+
+ for (i = 0; i < size; i++) {
+ error = (a[i] / (double)count) - 1.0;
+ printf("a[%4d] : %10d %.5f\n", i, a[i], error);
+ if (abs(error) > max_error) {
+ printf("Too much error\n");
+ exit(1);
+ }
+ }
+}
+
+#define MAX_SIZE 128
+
+int
+main()
+{
+ int a[MAX_SIZE];
+ int count = 1000000;
+ double max_error = .005;
+ int i;
+
+ for (i = 2; i <= MAX_SIZE; i *= 2) {
+ printf("\nTest %d\n\n", i);
+ test(a, i, count, max_error);
+ }
+
+ srand32(0);
+ for (i = 2; i <= MAX_SIZE; i *= 2) {
+ printf("\nTest %d\n\n", i);
+ test(a, i, count, max_error);
+ }
+
+ srand32(0xdeadbeef);
+ for (i = 2; i <= MAX_SIZE; i *= 2) {
+ printf("\nTest %d\n\n", i);
+ test(a, i, count, max_error);
+ }
+}
+
+#endif /* BASIC_TEST */
+
+#endif /* __TEST_RAND_C__ */
+
diff --git a/src/lib/common/string.c b/src/lib/common/string.c
new file mode 100644
index 0000000..7c82653
--- /dev/null
+++ b/src/lib/common/string.c
@@ -0,0 +1,189 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/common/string.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file string.c
+/// \brief strlen(), strcmp() etc. functions
+
+#include "string.h"
+
+/// Compute the length of a string
+///
+/// The strlen() function calculates the length of the string \a s, not
+/// including the terminating \b '\0' character. The strlen() function
+/// returns the number of characters in \a s.
+
+size_t
+strlen(const char *s)
+{
+ const char *p = s;
+
+ while (*p) {
+ p++;
+ }
+
+ return p - s;
+}
+
+
+/// Compare two strings
+///
+/// The strcmp() function compares the two strings \a s1 and \a s2. It
+/// returns an integer less than, equal to, or greater than zero if \a s1 is
+/// found, respectively, to be less than, to match, or be greater than \a s2.
+
+int
+strcmp(const char* s1, const char* s2)
+{
+ int rc;
+
+ if (s1 == s2) {
+ rc = 0;
+ } else {
+ while(*s1 && (*s1 == *s2)) {
+ s1++;
+ s2++;
+ }
+ rc = *((unsigned char *)s1) - *((unsigned char *)s2);
+ }
+ return rc;
+}
+
+
+/// Compare a portion of two strings
+///
+/// The strncmp() function compares at most the first \n characters of the two
+/// strings \a s1 and \a s2. It returns an integer less than, equal to, or
+/// greater than zero if (the prefix of) \a s1 is found, respectively, to be
+/// less than, to match, or be greater than (the prefix of) \a s2.
+
+int
+strncmp(const char* s1, const char* s2, size_t n)
+{
+ int rc;
+
+ if ((s1 == s2) || (n == 0)) {
+ rc = 0;
+ } else {
+ while(*s1 && (*s1 == *s2) && n--) {
+ s1++;
+ s2++;
+ }
+ rc = *((unsigned char *)s1) - *((unsigned char *)s2);
+ }
+ return rc;
+}
+
+
+/// Copy a string
+///
+/// The strcpy() function copies the string pointed to by \a src (including
+/// the terminating null character) to the array pointed to by \a dest. The
+/// strings may not overlap, and the destination string \a dest must be large
+/// enough to receive the copy.
+///
+/// The strcpy() function return a pointer to the destination string \a dest.
+
+char *
+strcpy(char *dest, const char *src)
+{
+ char *rv = dest;
+
+ while (*src) {
+ *dest++ = *src++;
+ }
+ *dest = '\0';
+
+ return rv;
+}
+
+
+/// Safely copy all or part of a string
+///
+/// The strncpy() function copies the string pointed to by \a src (including
+/// the terminating null character) to the array pointed to by \a dest, except
+/// that no more than \a n bytes of \a src are copied. This, if there is no
+/// null byte among the first \a n bytes of \a src, the result will not be
+/// null-terminated. In the case where the length of \a src is less than \a n,
+/// the remainder of \a dest will be padded with null bytes. The strings may
+/// not overlap.
+///
+/// The strncpy() function return a pointer to the destination string \a dest.
+
+char *
+strncpy(char *dest, const char *src, size_t n)
+{
+ char *rv = dest;
+
+ while (*src && n--) {
+ *dest++ = *src++;
+ }
+ memset(dest, 0, n);
+
+ return rv;
+}
+
+
+/// Compare two memory areas
+///
+/// The memcmp() function compares the first \a n bytes of the memory areas \a
+/// s1 and \a s2. It returns an integer less than, equal to, or greater than
+/// zero if \a s1 is found, respectively, to be less than, to match, or be
+/// greater than \a s2.
+int
+memcmp(const void* s1, const void* s2, size_t n)
+{
+ unsigned char *p1, *p2;
+ int rc;
+
+ p1 = (unsigned char*) s1;
+ p2 = (unsigned char*) s2;
+
+ if (s1 == s2) {
+
+ rc = 0;
+
+ } else {
+
+ while (n && (*p1 == *p2)) {
+ n--;
+ p1++;
+ p2++;
+ }
+
+ if (n == 0) {
+ rc = 0;
+ } else {
+ rc = (*p1 - *p2);
+ }
+ }
+
+ return rc;
+}
+
diff --git a/src/lib/common/string.h b/src/lib/common/string.h
new file mode 100644
index 0000000..5cfa470
--- /dev/null
+++ b/src/lib/common/string.h
@@ -0,0 +1,88 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/common/string.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __STRING_H__
+#define __STRING_H__
+
+// $Id: string.h,v 1.1.1.1 2013/12/11 20:49:20 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/lib/string.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file string.h
+/// \brief Replacement for <string.h>
+///
+/// The SSX library does not implement the entire <string.h> function.
+/// However the real reason for this header was the finding that under certain
+/// optimization modes, we were geting errors from the default <string.h>
+/// supplied with the MPC environment. So we created this replacement that
+/// only calls out what is implemented, exactly as it is implemented for SSX.
+
+#ifndef __ASSEMBLER__
+
+#include <stddef.h>
+
+// APIs inmplemented by string.c
+
+size_t
+strlen(const char *s);
+
+int
+strcmp(const char* s1, const char* s2);
+
+int
+strncmp(const char* s1, const char* s2, size_t n);
+
+int
+strcasecmp(const char* s1, const char* s2);
+
+int
+strncasecmp(const char* s1, const char* s2, size_t n);
+
+char *
+strcpy(char *dest, const char *src);
+
+char *
+strncpy(char *dest, const char *src, size_t n);
+
+void *
+memcpy(void *dest, const void *src, size_t n);
+
+void *
+memset(void *s, int c, size_t n);
+
+int
+memcmp(const void* s1, const void* s2, size_t n);
+
+// APIs implemented by strdup.c
+
+char *
+strdup(const char* s);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* __STRING_H__ */
diff --git a/src/lib/common/sync.c b/src/lib/common/sync.c
new file mode 100644
index 0000000..a489be8
--- /dev/null
+++ b/src/lib/common/sync.c
@@ -0,0 +1,294 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/common/sync.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id$
+
+/// \file sync.c
+/// \brief A library of higher-level synchronization primitives based on
+/// low-level kernel services.
+///
+/// The APIs provided here are currently based on kernel services, but the
+/// specifications should allow applications to be ported to other
+/// environments if required. Note that like kernel services, data
+/// structures manipulated by this code are protected in KERN_NONCRITICAL
+/// critical sections.
+
+#include "kernel.h"
+#include "sync.h"
+
+/// Create a Barrier
+///
+/// \param barrier A pointer to an uninitialized or currently unused Barrier
+///
+/// \param count The number of threads required to pend at the barrier before
+/// all threads are released again for execution. Note that \a count values
+/// of 0 and 1 are treated as equivalent - threads will not pend at all in
+/// these cases. Also note that if a watchdog thread is being used, the
+/// watchdog thread should not be included in the count.
+///
+/// \retval 0 Success
+///
+/// \retval -SYNC_INVALID_OBJECT The \a barrier is NULL (0)
+
+int
+barrier_create(Barrier *barrier, KERN_SEMAPHORE_COUNT count)
+{
+ if (KERN_ERROR_CHECK_API) {
+ KERN_ERROR_IF(barrier == 0, SYNC_INVALID_OBJECT);
+ }
+
+ barrier->entry_sem = &(barrier->sem[0]);
+ barrier->exit_sem = &(barrier->sem[1]);
+
+ KERN_SEMAPHORE_CREATE((KERN_SEMAPHORE *)(barrier->entry_sem), 0, 0);
+ KERN_SEMAPHORE_CREATE((KERN_SEMAPHORE *)(barrier->exit_sem), 0, 0);
+
+ barrier->entry_count = 0;
+ barrier->exit_count = 0;
+ barrier->target_count = count;
+
+ barrier->watchdog_pending = 0;
+ barrier->watchdog_entries = 0;
+
+ barrier->callback = 0;
+ barrier->arg = 0;
+ barrier->run_callback = 0;
+
+ return 0;
+}
+
+
+/// Install a barrier callback
+///
+/// \param barrier A pointer to an initialized Barrier object
+///
+/// \param callback A function taking a single (void *) argument, to be
+/// executed in the context of the first thread to exit the barrier when the
+/// barrier condition is met.
+///
+/// \param arg The argument of the \a callback.
+///
+/// The Barrier object supports an optional callback function. The callback
+/// (with the customary single (void *) parameter) is made when the barrier
+/// condition is met, in the thread context of the first (highest priority)
+/// thread to exit the barrier. The callback is made inside the barrier_pend()
+/// call, but outside of a critical section. The specification of the callback
+/// is not part of the barrier_create() call, but is provided later by this
+/// API. Setting a NULL (0) callback disables the callback mechanism.
+///
+/// \retval 0 Success
+///
+/// \retval -SYNC_INVALID_OBJECT The \a barrier is NULL (0)
+
+int
+barrier_callback_set(Barrier *barrier,
+ BarrierCallback callback,
+ void *arg)
+{
+ KERN_MACHINE_CONTEXT ctx;
+
+ if (KERN_ERROR_CHECK_API) {
+ KERN_ERROR_IF(barrier == 0, SYNC_INVALID_OBJECT);
+ }
+
+ KERN_CRITICAL_SECTION_ENTER(KERN_NONCRITICAL, &ctx);
+
+ barrier->callback = callback;
+ barrier->arg = arg;
+
+ KERN_CRITICAL_SECTION_EXIT(&ctx);
+
+ return 0;
+}
+
+
+static int
+_barrier_pend(Barrier *barrier, int watchdog)
+{
+ KERN_MACHINE_CONTEXT ctx;
+ int rc = 0;
+ KERN_SEMAPHORE *temp_sem;
+ BarrierCallback callback = 0; /* Make GCC Happy */
+ void *arg = 0; /* Make GCC Happy */
+ int run_callback;
+
+ if (KERN_ERROR_CHECK_API) {
+ KERN_ERROR_IF(barrier == 0, SYNC_INVALID_OBJECT);
+ }
+
+ KERN_CRITICAL_SECTION_ENTER(KERN_NONCRITICAL, &ctx);
+
+ // A normal thread will pend at the entry unless 1) the thread satisfies
+ // the barrier condition, or 2) a watchdog thread is pending here. A
+ // watchdog thread only pends if no other threads are pending.
+
+ if (watchdog) {
+ barrier->watchdog_entries++;
+ }
+
+ barrier->entry_count++;
+ if (!barrier->watchdog_pending &&
+ ((watchdog && (barrier->entry_count == 1)) ||
+ (!watchdog && (barrier->entry_count < barrier->target_count)))) {
+
+ if (watchdog) {
+ barrier->watchdog_pending = 1;
+ }
+
+ // The thread must pend here
+
+ rc = KERN_SEMAPHORE_PEND((KERN_SEMAPHORE *)(barrier->entry_sem),
+ KERN_WAIT_FOREVER);
+ if (rc) {
+ goto exit_critical;
+ }
+
+ } else {
+
+ // The barrier condition is met - or the watchdog thread is blocked
+ // here. The entry and exit semaphores and counts are swapped. The
+ // callback is marked to be called.
+
+ // If the barrier is used incorrectly, or threads are deleted without
+ // adjusting the barrier target count then the following condition
+ // could become true, which could lead to bad behavior.
+
+ if (barrier->exit_count != 0) {
+ KERN_PANIC(SYNC_BARRIER_INVARIANT);
+ }
+
+ barrier->entry_count--; // Undo preincrement above
+ barrier->watchdog_pending = 0;
+
+ temp_sem = (KERN_SEMAPHORE *)(barrier->exit_sem);
+ barrier->exit_sem = barrier->entry_sem;
+ barrier->entry_sem = temp_sem;
+
+ barrier->exit_count = barrier->entry_count;
+ barrier->entry_count = 0;
+
+ barrier->run_callback = 1;
+ }
+
+ // This thread either continues to run or just woke up after having
+ // blocked at the barrier. The current thread makes the next thread (if
+ // any) runnable as well. Normally the current thread will be of a higher
+ // priority than any blocked threads, so no context switch will occur. The
+ // thread that satisfies the barrier condition \e will cause a context
+ // switch here, unless it just happens to be the highest priority thread
+ // in the barrier group.
+
+ if (barrier->exit_count != 0) {
+ barrier->exit_count--;
+ rc = KERN_SEMAPHORE_POST((KERN_SEMAPHORE *)(barrier->exit_sem));
+ }
+
+exit_critical:
+
+ if (rc) {
+ KERN_CRITICAL_SECTION_EXIT(&ctx);
+ return rc;
+ }
+
+ // In the case of a satisfied barrier condition, the first thread to exit
+ // the critical section will be the higest priority thread blocked at the
+ // barrier. This thread is tasked with executing the callback, outside of
+ // the critical section.
+
+ run_callback = barrier->run_callback;
+ barrier->run_callback = 0;
+ if (run_callback) {
+ callback = barrier->callback;
+ arg = (void *)(barrier->arg); /* Cast away 'volatile' */
+ }
+
+ KERN_CRITICAL_SECTION_EXIT(&ctx);
+
+ if (run_callback && callback) {
+ callback(arg);
+ }
+
+ return 0;
+}
+
+
+/// Pend at a Barrier
+///
+/// \param barrier An initialized barrier object
+///
+/// A thread will pend at a barrier until \a count number of threads (supplied
+/// in the call of barrier_create()) are pending. If \a count is 0 or 1, the
+/// API always returns immediately.
+///
+/// If barrier watchdog thread is being used (correctly), then the watchdog
+/// will cause thread pending on the barrier to be released whenever all
+/// threads in the group are blocked, regardless of whether some of the
+/// group's threads are blocked elesewhere.
+///
+/// \retval 0 Success
+///
+/// \retval -SYNC_INVALID_OBJECT The \a barrier is NULL (0)
+///
+/// Other errors may be returned by the embedded call of ssx_semephore_pend().
+/// In particular this API will fail if called outside of a thread context
+/// since it requires blocking indefinitely on a semaphore.
+///
+/// \bug The semaphore should be able to provide the number of pending threads
+/// - which we should really be using here instead of the barrier counts. The
+/// current implementation can produce some strange behavior if threads are
+/// deleted.
+
+int
+barrier_pend(Barrier *barrier)
+{
+ return _barrier_pend(barrier, 0);
+}
+
+
+/// Barrier watchdog thread
+///
+/// \param arg A pointer to the Barrier object this thread should manage.
+///
+/// A barrier_watchdog() thread is attached to a Barrier object, and forces
+/// the barrier condition to be met whenever it runs. This thread is designed
+/// to be mapped at a priority immediately below the priorities of a group of
+/// threads that pend on the barrier.
+///
+/// In this way, should every thread in the group become blocked, the watchdog
+/// will allow any threads that are blocked on the barrier to run. If all the
+/// threads are blocked elsewhere, then the watchdog blocks on the barrier,
+/// and as soon as any thread pends again at the barrier the thread remains
+/// runnable and the watchdog becomes runnable.
+///
+/// The barrier_watchdog() thread is not required. Without the watchdog,
+/// otherwise runnable threads in the barrier group will remain blocked on the
+/// barrier as long as any of their cohorts remain blocked elsewhere.
+
+void
+barrier_watchdog(void *arg)
+{
+ do {
+ _barrier_pend((Barrier *)arg, 1);
+ } while (1);
+}
diff --git a/src/lib/common/sync.h b/src/lib/common/sync.h
new file mode 100644
index 0000000..5657c78
--- /dev/null
+++ b/src/lib/common/sync.h
@@ -0,0 +1,167 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/common/sync.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __SYNC_H__
+#define __SYNC_H__
+
+// $Id$
+
+/// \file sync.h
+/// \brief A library of higher-level synchronization primitives based on
+/// low-level kernel services.
+///
+/// The APIs provided here are currently based on SSX services, but the
+/// specifications should allow applications to be fairly easily ported to
+/// other environments if required.
+///
+/// \todo Consider implementing a subset of the POSIX pthreads standards
+/// instead of these non-standard synchronization primitives. Ideally all
+/// synchronization primitives would be part of the SSX kernel so that they
+/// would correctly handle thread suspension and deletion while pending.
+
+#include "kernel.h"
+
+// Error/panic codes
+
+#define SYNC_INVALID_OBJECT 0x00896201
+#define SYNC_INVALID_ARGUMENT 0x00896202
+#define SYNC_BARRIER_PEND_TIMED_OUT 0x00896203
+#define SYNC_BARRIER_OVERFLOW 0x00896204
+#define SYNC_BARRIER_UNDERFLOW 0x00896205
+#define SYNC_BARRIER_INVARIANT 0x00896206
+#define SYNC_SHARED_UNDERFLOW 0x00896207
+
+////////////////////////////////////////////////////////////////////////////
+// Barrier
+////////////////////////////////////////////////////////////////////////////
+
+typedef void (*BarrierCallback)(void *);
+
+/// A thread barrier object
+///
+/// A Barrier allows multiple threads to pend until a group of threads are all
+/// pending at the barrier. Once all threads are pending at the barrier, all
+/// threads are released again for execution. The barrier guarantees that
+/// once released, lower-priority threads will have the chance to execute
+/// before the barrier condition is satisfied again. Thus the Barrier can be
+/// used as a form of fair scheduling for a group of threads that execute in a
+/// loop of doing work followed by pending at the barrier.
+///
+/// Although the barrier guarantees fairness, it can not by itself guarantee
+/// progress. If several threads in a barrier group are
+/// pending at the barrier while other threads in the group are blocked away
+/// from the barrier, the threads at the barrier should be running (if allowed
+/// by the priority mappings etc.). The only way to guarantee constant
+/// progress by any unblocked thread in a group is to created another,
+/// 'watchdog' thread that has lower priority than the other threads in the
+/// group. The watchdog thread only executes when all threads in the group
+/// are blocked, and ensures progress. This implementation provides a
+/// watchdog thread routine as barrier_watchdog().
+///
+/// Normally the threads in a barrier group will be assigned consecutive
+/// priorities - otherwise various forms of priority inversion can arise. The
+/// watchdog thread, if any, will normally be assigned the priority
+/// immediately lower than the lowest priority thread in the group.
+///
+/// The Barrier object supports an optional callback function. The callback
+/// (with the customary single (void *) parameter) is made when the barrier
+/// condition is met, in the thread context of the first (highest priority)
+/// thread to exit the barrier. The callback is made inside the barrier_pend()
+/// call, but outside of a critical section. The specification of the callback
+/// is not part of the barrier_create() call, but is provided later by the
+/// barrier_callback_set() call. A NULL (0) callback (the default) is ignored.
+///
+/// NB: All barrier APIs (other than barrier_create()) must be made from
+/// thread mode - they will fail if called from interrupt handlers or before
+/// threads have started.
+
+typedef struct Barrier {
+
+ /// Semaphore array; see \a entry_sem and \a exit_sem;
+ KERN_SEMAPHORE sem[2];
+
+ /// The entry semaphore.
+ ///
+ /// Threads pending at the barrier initially block here. Once all of the
+ /// threads in the group are pending here, the entry and exit semaphores
+ /// are swapped and threads are released (in priority order) from the new
+ /// exit semaphore.
+ volatile KERN_SEMAPHORE *entry_sem;
+
+ /// The exit semaphore.
+ volatile KERN_SEMAPHORE *exit_sem;
+
+ /// The current count of threads pending at \a entry_sem.
+ volatile KERN_SEMAPHORE_COUNT entry_count;
+
+ /// The current count of threads pending at \a exit_sem.
+ volatile KERN_SEMAPHORE_COUNT exit_count;
+
+ /// The target number of threads required to release the barrier
+ volatile KERN_SEMAPHORE_COUNT target_count;
+
+ /// A flag - Is the watchdog thread pending at the barrier?
+ volatile int watchdog_pending;
+
+ /// Statistics - The number of times the watchdog has entered the barrier.
+ volatile uint32_t watchdog_entries;
+
+ /// The barrier condition callback function
+ volatile BarrierCallback callback;
+
+ /// The argument of the callback function
+ volatile void *arg;
+
+ /// This flag is set to tell the first thread to exit the barrier to
+ /// execute the callback (if any).
+ volatile int run_callback;
+
+} Barrier;
+
+int
+barrier_create(Barrier *barrier, KERN_SEMAPHORE_COUNT count);
+
+int
+barrier_callback_set(Barrier *barrier,
+ BarrierCallback callback,
+ void *arg);
+
+int
+barrier_pend(Barrier *barrier);
+
+void
+barrier_watchdog(void *arg);
+
+
+#endif // __SYNC_H__
+
+
+
+
+
+
+
+
+
+
OpenPOWER on IntegriCloud