From 9cfb20d63d9be99e0f60691144c3a30465d9800a Mon Sep 17 00:00:00 2001 From: Wolfgang Puffitsch Date: Fri, 15 Aug 2014 16:49:22 +0200 Subject: [PATCH 1/8] Use separate reentrancy structures for each core. --- libgloss/patmos/crt0.c | 22 ++++++++++++++++++++++ newlib/libc/include/sys/config.h | 5 +++++ 2 files changed, 27 insertions(+) diff --git a/libgloss/patmos/crt0.c b/libgloss/patmos/crt0.c index aedf733..546a1c0 100644 --- a/libgloss/patmos/crt0.c +++ b/libgloss/patmos/crt0.c @@ -16,6 +16,7 @@ // (COPYING3.LIB). If not, see . #include +#include #include "patmos.h" @@ -67,6 +68,11 @@ unsigned _loader_baseaddr[MAX_CORES]; /// _loader_off - the offset of the loading function (one per core) unsigned _loader_off[MAX_CORES]; +/// _reent_ptr - data structure for reentrant library calls +struct _reent _reent_data [MAX_CORES]; +/// __initreent - initialize reentrancy structure +void __initreent(struct _reent *ptr) __attribute__((noinline)); + //****************************************************************************** /// _start - main entry function to all patmos executables. /// Setup the stack frame, initialize data structures, invoke main, et cetera. @@ -110,6 +116,10 @@ void _start() // clear the BSS section // memset(&__bss_start, 0, &_end - &__bss_start); + // --------------------------------------------------------------------------- + // initialize reentrancy structure + __initreent(__getreent()); + // --------------------------------------------------------------------------- // call initializers __init(); @@ -149,3 +159,15 @@ void __fini(void) { (*i)(); } } + +/// __initreent - initialize reentrancy structure +void __initreent(struct _reent *ptr) { + _REENT_INIT_PTR(ptr); +} + +/// __getreent - get reentrancy structure for current thread +struct _reent *__getreent(void) +{ + const int id = *((_iodev_ptr_t)(&_cpuinfo_base+0x0)); + return &_reent_data[id]; +} diff --git a/newlib/libc/include/sys/config.h b/newlib/libc/include/sys/config.h index 49c81f9..dcee1e6 100644 --- a/newlib/libc/include/sys/config.h +++ b/newlib/libc/include/sys/config.h @@ -92,6 +92,11 @@ #endif #endif +#ifdef __patmos__ +/* we want the reentrancy structure to be returned by a function */ +#define __DYNAMIC_REENT__ +#endif + #ifdef __mn10200__ #define __SMALL_BITFIELDS #endif From 152a0ee7a4381b8e6cbf440e3fe08e03a70d8644 Mon Sep 17 00:00:00 2001 From: Wolfgang Puffitsch Date: Fri, 15 Aug 2014 19:26:37 +0200 Subject: [PATCH 2/8] A locking implementation based on Lamport's bakery. --- libgloss/patmos/Makefile.in | 2 +- libgloss/patmos/lock.c | 128 ++++++++++++++++++++++++++ newlib/libc/machine/patmos/sys/lock.h | 70 ++++++++++++++ 3 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 libgloss/patmos/lock.c create mode 100644 newlib/libc/machine/patmos/sys/lock.h diff --git a/libgloss/patmos/Makefile.in b/libgloss/patmos/Makefile.in index bfce222..d6340cb 100644 --- a/libgloss/patmos/Makefile.in +++ b/libgloss/patmos/Makefile.in @@ -69,7 +69,7 @@ SIM_BSP = libpatmos.a SIM_CRTS = crt0.o crtbegin.o crtend.o SIM_OBJS = open.o close.o read.o write.o lseek.o link.o unlink.o fstat.o\ isatty.o getpid.o exec.o fork.o wait.o kill.o exit.o sbrk.o\ - times.o ftruncate.o stat.o chown.o chmod.o + times.o ftruncate.o stat.o chown.o chmod.o lock.o SIM_INSTALL = install-sim # Host specific makefile fragment comes in here. diff --git a/libgloss/patmos/lock.c b/libgloss/patmos/lock.c new file mode 100644 index 0000000..04b8bc6 --- /dev/null +++ b/libgloss/patmos/lock.c @@ -0,0 +1,128 @@ +// Copyright 2014 Technical University of Denmark, DTU Compute. +// +// This file is part of the newlib C library for the Patmos processor. +// +// This file is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This code is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// (COPYING3.LIB). If not, see . + +#include +#include + +#include + +/* This locking implementation uses Lamport's baker algorithm. + * + * Rationale: It is faster than Peterson's generalized algorithm for N + * threads. Lamport's "fast" algorithm would be much faster for + * uncontended locks, but is not starvation-free. + * + * Caveat: The "number" field in the locking structure may be + * unbounded if a lock is continuously acquired/released without ever + * being free. + */ + +int __patmos_lock_init(_LOCK_T *lock) { + _UNCACHED _LOCK_T *ll = (_UNCACHED _LOCK_T *)lock; + for (unsigned i = 0; i < sizeof(ll->entering)/sizeof(ll->entering[0]); i++) { + ll->entering[i] = 0; + } + for (unsigned i = 0; i < sizeof(ll->number)/sizeof(ll->number[0]); i++) { + ll->number[i] = 0; + } + return 0; +} + +int __patmos_lock_init_recursive(_LOCK_RECURSIVE_T *lock) { + __lock_init(lock->lock); + _UNCACHED _LOCK_RECURSIVE_T *ll = (_UNCACHED _LOCK_RECURSIVE_T *)lock; + ll->owner = 0; + ll->depth = 0; + return 0; +} + +int __patmos_lock_close(_LOCK_T *lock) { + return 0; +} + +int __patmos_lock_close_recursive(_LOCK_RECURSIVE_T *lock) { + __lock_close(lock->lock); + return 0; +} + +static unsigned max(_UNCACHED _LOCK_T *ll) { + unsigned m = 0; + for (unsigned i = 0; i < sizeof(ll->number)/sizeof(ll->number[0]); i++) { + unsigned n = ll->number[i]; + m = n > m ? n : m; + } + return m; +} + +int __patmos_lock_acquire(_LOCK_T *lock) { + unsigned char id = get_cpuid(); + _UNCACHED _LOCK_T *ll = (_UNCACHED _LOCK_T *)lock; + + ll->entering[id] = 1; + unsigned n = 1 + max(ll); + ll->number[id] = n; + ll->entering[id] = 0; + + for (unsigned j = 0; j < sizeof(ll->number)/sizeof(ll->number[0]); j++) { + while (ll->entering[j]) { + /* busy wait */ + } + unsigned m = ll->number[j]; + while ((m != 0) && + ((m < n) || ((m == n) && (j < id)))) { + /* busy wait, only update m */ + m = ll->number[j]; + } + } + + return 0; +} + +int __patmos_lock_release(_LOCK_T *lock) { + unsigned char id = get_cpuid(); + _UNCACHED _LOCK_T *ll = (_UNCACHED _LOCK_T *)lock; + + ll->number[id] = 0; // exit section + + return 0; +} + +int __patmos_lock_acquire_recursive(_LOCK_RECURSIVE_T *lock) { + unsigned char id = get_cpuid(); + _UNCACHED _LOCK_RECURSIVE_T *ll = (_UNCACHED _LOCK_RECURSIVE_T *)lock; + + if (ll->owner != id || ll->depth == 0) { + __lock_acquire(lock->lock); + ll->owner = id; + } + + ll->depth++; + + return 0; +} + +int __patmos_lock_release_recursive(_LOCK_RECURSIVE_T *lock) { + _UNCACHED _LOCK_RECURSIVE_T *ll = (_UNCACHED _LOCK_RECURSIVE_T *)lock; + + ll->depth--; + + if (ll->depth == 0) { + __lock_release(lock->lock); + } + + return 0; +} diff --git a/newlib/libc/machine/patmos/sys/lock.h b/newlib/libc/machine/patmos/sys/lock.h new file mode 100644 index 0000000..b27ef6d --- /dev/null +++ b/newlib/libc/machine/patmos/sys/lock.h @@ -0,0 +1,70 @@ +// Copyright 2014 Technical University of Denmark, DTU Compute. +// +// This file is part of the newlib C library for the Patmos processor. +// +// This file is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This code is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// (COPYING3.LIB). If not, see . + +#ifndef __SYS_LOCK_H__ +#define __SYS_LOCK_H__ + +#ifndef MAX_CORES +#define MAX_CORES 64 +#endif + +/* Locking structure to match Lamport's bakery locks */ +typedef struct { + volatile unsigned char entering [MAX_CORES]; + volatile unsigned int number [MAX_CORES]; +} _LOCK_T; + +typedef struct { + _LOCK_T lock; + volatile unsigned char owner; + volatile unsigned int depth; +} _LOCK_RECURSIVE_T; + + +#define __EMPTY_LOCK { { 0 }, { 0 } } + +#define __LOCK_INIT(class,lock) \ + class _LOCK_T lock = __EMPTY_LOCK; +#define __LOCK_INIT_RECURSIVE(class,lock) \ + class _LOCK_RECURSIVE_T lock = { __EMPTY_LOCK, 0, 0 }; + + +#define __lock_init(lock) __patmos_lock_init(&(lock)) +#define __lock_init_recursive(lock) __patmos_lock_init_recursive(&(lock)) +#define __lock_close(lock) __patmos_lock_close(&(lock)) +#define __lock_close_recursive(lock) __patmos_lock_close_recursive(&(lock)) +#define __lock_acquire(lock) __patmos_lock_acquire(&(lock)) +#define __lock_acquire_recursive(lock) __patmos_lock_acquire_recursive(&(lock)) +#define __lock_try_acquire(lock) __patmos_lock_try_acquire(&(lock)) +#define __lock_try_acquire_recursive(lock) __patmos_lock_try_acquire_recursive(&(lock)) +#define __lock_release(lock) __patmos_lock_release(&(lock)) +#define __lock_release_recursive(lock) __patmos_lock_release_recursive(&(lock)) + + +extern int __patmos_lock_init(_LOCK_T *lock); +extern int __patmos_lock_init_recursive(_LOCK_RECURSIVE_T *lock); +extern int __patmos_lock_close(_LOCK_T *lock); +extern int __patmos_lock_close_recursive(_LOCK_RECURSIVE_T *lock); +extern int __patmos_lock_acquire(_LOCK_T *lock); +extern int __patmos_lock_acquire_recursive(_LOCK_RECURSIVE_T *lock); +extern int __patmos_lock_try_acquire(_LOCK_T *lock); +extern int __patmos_lock_try_acquire_recursive(_LOCK_RECURSIVE_T *lock); +extern int __patmos_lock_release(_LOCK_T *lock); +extern int __patmos_lock_release_recursive(_LOCK_RECURSIVE_T *lock); + +#endif /* __SYS_LOCK_H__ */ + From df3e757e0e1bf903996f214df7b4e984f61ec145 Mon Sep 17 00:00:00 2001 From: Wolfgang Puffitsch Date: Mon, 18 Aug 2014 18:49:08 +0200 Subject: [PATCH 3/8] Make sure lock owner is invalid when lock is not held. --- libgloss/patmos/lock.c | 3 ++- newlib/libc/machine/patmos/sys/lock.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libgloss/patmos/lock.c b/libgloss/patmos/lock.c index 04b8bc6..076874e 100644 --- a/libgloss/patmos/lock.c +++ b/libgloss/patmos/lock.c @@ -45,7 +45,7 @@ int __patmos_lock_init(_LOCK_T *lock) { int __patmos_lock_init_recursive(_LOCK_RECURSIVE_T *lock) { __lock_init(lock->lock); _UNCACHED _LOCK_RECURSIVE_T *ll = (_UNCACHED _LOCK_RECURSIVE_T *)lock; - ll->owner = 0; + ll->owner = -1; ll->depth = 0; return 0; } @@ -121,6 +121,7 @@ int __patmos_lock_release_recursive(_LOCK_RECURSIVE_T *lock) { ll->depth--; if (ll->depth == 0) { + ll->owner = -1; // reset owner to invalid ID __lock_release(lock->lock); } diff --git a/newlib/libc/machine/patmos/sys/lock.h b/newlib/libc/machine/patmos/sys/lock.h index b27ef6d..e1a9204 100644 --- a/newlib/libc/machine/patmos/sys/lock.h +++ b/newlib/libc/machine/patmos/sys/lock.h @@ -40,7 +40,7 @@ typedef struct { #define __LOCK_INIT(class,lock) \ class _LOCK_T lock = __EMPTY_LOCK; #define __LOCK_INIT_RECURSIVE(class,lock) \ - class _LOCK_RECURSIVE_T lock = { __EMPTY_LOCK, 0, 0 }; + class _LOCK_RECURSIVE_T lock = { __EMPTY_LOCK, -1, 0 }; #define __lock_init(lock) __patmos_lock_init(&(lock)) From 99e7dd0fbb670f197da8722a9aa13654e74c2b18 Mon Sep 17 00:00:00 2001 From: Wolfgang Puffitsch Date: Tue, 19 Aug 2014 16:58:45 +0200 Subject: [PATCH 4/8] Support for invalidating data and method cache. --- newlib/libc/machine/patmos/machine/patmos.h | 25 +++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/newlib/libc/machine/patmos/machine/patmos.h b/newlib/libc/machine/patmos/machine/patmos.h index e842f7b..30d5bd7 100644 --- a/newlib/libc/machine/patmos/machine/patmos.h +++ b/newlib/libc/machine/patmos/machine/patmos.h @@ -22,7 +22,7 @@ #define _MACHPATMOS_H /** - * Base address of the IO address range. + * Base address of the CPU info device. * Defined by patmos-clang driver as a symbol at link-time */ extern char _cpuinfo_base; @@ -66,12 +66,29 @@ static inline unsigned int get_cpu_freq() /** - * Flush the data cache state. + * Base address of the exception unit. */ -static inline void flush_data_cache() +extern char _excunit_base; + +/** + * The cache control register (in the exception unit). + */ +#define CACHE_CONTROL (*((_iodev_ptr_t)(&_excunit_base+0x14))) + +/** + * Invalidate the data cache. + */ +static inline void inval_dcache() { - // TODO implement + CACHE_CONTROL = 0x01; } +/** + * Invalidate the method cache. + */ +static inline void inval_mcache() +{ + CACHE_CONTROL = 0x02; +} #endif /* _MACHPATMOS_H */ From 1dbe9d96a1a5ad05691da34f34ea60bae813dd08 Mon Sep 17 00:00:00 2001 From: Wolfgang Puffitsch Date: Tue, 19 Aug 2014 16:59:27 +0200 Subject: [PATCH 5/8] Invalidate data cache when acquiring lock. --- libgloss/patmos/lock.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libgloss/patmos/lock.c b/libgloss/patmos/lock.c index 076874e..6730555 100644 --- a/libgloss/patmos/lock.c +++ b/libgloss/patmos/lock.c @@ -89,6 +89,9 @@ int __patmos_lock_acquire(_LOCK_T *lock) { } } + // invalidate data cache to establish cache coherence + inval_dcache(); + return 0; } From 84a0768b23a589a6ad5484728f20d9894907d9f7 Mon Sep 17 00:00:00 2001 From: Wolfgang Puffitsch Date: Thu, 21 Aug 2014 14:00:07 +0200 Subject: [PATCH 6/8] Allocate reentrancy structures with malloc(). --- libgloss/patmos/crt0.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/libgloss/patmos/crt0.c b/libgloss/patmos/crt0.c index 546a1c0..9888794 100644 --- a/libgloss/patmos/crt0.c +++ b/libgloss/patmos/crt0.c @@ -16,6 +16,7 @@ // (COPYING3.LIB). If not, see . #include +#include #include #include "patmos.h" @@ -69,9 +70,9 @@ unsigned _loader_baseaddr[MAX_CORES]; unsigned _loader_off[MAX_CORES]; /// _reent_ptr - data structure for reentrant library calls -struct _reent _reent_data [MAX_CORES]; +struct _reent *_reent_ptr [MAX_CORES]; /// __initreent - initialize reentrancy structure -void __initreent(struct _reent *ptr) __attribute__((noinline)); +void __initreent(void) __attribute__((noinline)); //****************************************************************************** /// _start - main entry function to all patmos executables. @@ -118,7 +119,7 @@ void _start() // --------------------------------------------------------------------------- // initialize reentrancy structure - __initreent(__getreent()); + __initreent(); // --------------------------------------------------------------------------- // call initializers @@ -161,13 +162,15 @@ void __fini(void) { } /// __initreent - initialize reentrancy structure -void __initreent(struct _reent *ptr) { - _REENT_INIT_PTR(ptr); +void __initreent(void) { + const int id = *((_iodev_ptr_t)(&_cpuinfo_base+0x0)); + _reent_ptr[id] = malloc(sizeof(struct _reent)); + _REENT_INIT_PTR(_reent_ptr[id]); } /// __getreent - get reentrancy structure for current thread struct _reent *__getreent(void) { const int id = *((_iodev_ptr_t)(&_cpuinfo_base+0x0)); - return &_reent_data[id]; + return _reent_ptr[id]; } From 25c031404571cfeda1640c51e73e73413ec761c5 Mon Sep 17 00:00:00 2001 From: Wolfgang Puffitsch Date: Thu, 21 Aug 2014 14:00:50 +0200 Subject: [PATCH 7/8] Add define to avoid any global reentrancy structure. --- newlib/configure.host | 1 + newlib/libc/include/sys/reent.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/newlib/configure.host b/newlib/configure.host index f3efb5b..0569de3 100644 --- a/newlib/configure.host +++ b/newlib/configure.host @@ -699,6 +699,7 @@ case "${host}" in newlib_cflags="${newlib_cflags} -D_NO_GETLOGIN -D_NO_GETPWENT -D_NO_GETUT -D_NO_GETPASS -D_NO_SIGSET -D_NO_WORDEXP -D_NO_POPEN -D_NO_GLOB -D_NO_EXECVE" # We do not support directories, disable compiling stand-in functions newlib_cflags="${newlib_cflags} -DHAVE_OPENDIR" + newlib_cflags="${newlib_cflags} -D_REENT_NOGLOBAL" ;; powerpc*-*-eabialtivec*) default_newlib_io_long_long="yes" diff --git a/newlib/libc/include/sys/reent.h b/newlib/libc/include/sys/reent.h index 8518964..397207a 100644 --- a/newlib/libc/include/sys/reent.h +++ b/newlib/libc/include/sys/reent.h @@ -816,7 +816,9 @@ struct _reent #endif extern struct _reent *_impure_ptr __ATTRIBUTE_IMPURE_PTR__; +#ifndef _REENT_NOGLOBAL extern struct _reent *_CONST _global_impure_ptr __ATTRIBUTE_IMPURE_PTR__; +#endif void _reclaim_reent _PARAMS ((struct _reent *)); @@ -835,7 +837,11 @@ void _reclaim_reent _PARAMS ((struct _reent *)); #endif /* !_REENT_ONLY */ +#ifndef _REENT_NOGLOBAL #define _GLOBAL_REENT _global_impure_ptr +#else +#define _GLOBAL_REENT _REENT +#endif #ifdef __cplusplus } From de3eacdb5a680453a0e96540aba3f07131cb5dbb Mon Sep 17 00:00:00 2001 From: Wolfgang Puffitsch Date: Fri, 22 Aug 2014 11:43:12 +0200 Subject: [PATCH 8/8] No locking or reentrancy structures when compiling for RTEMS. --- newlib/libc/include/sys/config.h | 2 +- newlib/libc/machine/patmos/sys/lock.h | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/newlib/libc/include/sys/config.h b/newlib/libc/include/sys/config.h index dcee1e6..6c5d4b3 100644 --- a/newlib/libc/include/sys/config.h +++ b/newlib/libc/include/sys/config.h @@ -92,7 +92,7 @@ #endif #endif -#ifdef __patmos__ +#if defined(__patmos__) && !defined(__rtems__) /* we want the reentrancy structure to be returned by a function */ #define __DYNAMIC_REENT__ #endif diff --git a/newlib/libc/machine/patmos/sys/lock.h b/newlib/libc/machine/patmos/sys/lock.h index e1a9204..8fbc558 100644 --- a/newlib/libc/machine/patmos/sys/lock.h +++ b/newlib/libc/machine/patmos/sys/lock.h @@ -18,6 +18,8 @@ #ifndef __SYS_LOCK_H__ #define __SYS_LOCK_H__ +#ifndef __rtems__ + #ifndef MAX_CORES #define MAX_CORES 64 #endif @@ -66,5 +68,29 @@ extern int __patmos_lock_try_acquire_recursive(_LOCK_RECURSIVE_T *lock); extern int __patmos_lock_release(_LOCK_T *lock); extern int __patmos_lock_release_recursive(_LOCK_RECURSIVE_T *lock); +#else /* __rtems__ */ + +/* TODO: these are just dummies, replace with actual RTEMS locking functions */ + +typedef int _LOCK_T; +typedef int _LOCK_RECURSIVE_T; + +#include <_ansi.h> + +#define __LOCK_INIT(class,lock) static int lock = 0; +#define __LOCK_INIT_RECURSIVE(class,lock) static int lock = 0; +#define __lock_init(lock) (_CAST_VOID 0) +#define __lock_init_recursive(lock) (_CAST_VOID 0) +#define __lock_close(lock) (_CAST_VOID 0) +#define __lock_close_recursive(lock) (_CAST_VOID 0) +#define __lock_acquire(lock) (_CAST_VOID 0) +#define __lock_acquire_recursive(lock) (_CAST_VOID 0) +#define __lock_try_acquire(lock) (_CAST_VOID 0) +#define __lock_try_acquire_recursive(lock) (_CAST_VOID 0) +#define __lock_release(lock) (_CAST_VOID 0) +#define __lock_release_recursive(lock) (_CAST_VOID 0) + +#endif + #endif /* __SYS_LOCK_H__ */