diff options
author | William Bryan <wilbryan@us.ibm.com> | 2015-08-03 12:38:58 -0500 |
---|---|---|
committer | William A. Bryan <wilbryan@us.ibm.com> | 2015-08-03 15:32:27 -0500 |
commit | 420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3 (patch) | |
tree | c9f6691eddba39193e39aa769367e1267fb9fc86 /src/lib/common | |
parent | adade8c8ef30ed519322674c762d95663009c5d4 (diff) | |
download | talos-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/Makefile | 57 | ||||
-rw-r--r-- | src/lib/common/README.txt | 1 | ||||
-rw-r--r-- | src/lib/common/kernel.h | 363 | ||||
-rw-r--r-- | src/lib/common/libcommonfiles.mk | 54 | ||||
-rw-r--r-- | src/lib/common/memcpy.c | 102 | ||||
-rw-r--r-- | src/lib/common/memset.c | 142 | ||||
-rw-r--r-- | src/lib/common/rand.h | 124 | ||||
-rw-r--r-- | src/lib/common/rand32.c | 384 | ||||
-rw-r--r-- | src/lib/common/string.c | 189 | ||||
-rw-r--r-- | src/lib/common/string.h | 88 | ||||
-rw-r--r-- | src/lib/common/sync.c | 294 | ||||
-rw-r--r-- | src/lib/common/sync.h | 167 |
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__ + + + + + + + + + + |