diff options
-rw-r--r-- | sim/ppc/ChangeLog | 8 | ||||
-rw-r--r-- | sim/ppc/Makefile.in | 2 | ||||
-rwxr-xr-x | sim/ppc/configure | 259 | ||||
-rw-r--r-- | sim/ppc/configure.ac | 100 | ||||
-rw-r--r-- | sim/ppc/debug.c | 5 | ||||
-rw-r--r-- | sim/ppc/debug.h | 2 | ||||
-rw-r--r-- | sim/ppc/hw_sem.c | 289 | ||||
-rw-r--r-- | sim/ppc/hw_shm.c | 236 |
8 files changed, 894 insertions, 7 deletions
diff --git a/sim/ppc/ChangeLog b/sim/ppc/ChangeLog index 7517c86..17f50cf 100644 --- a/sim/ppc/ChangeLog +++ b/sim/ppc/ChangeLog @@ -1,3 +1,11 @@ +2008-11-18 Joel Sherrill <joel.sherrill@oarcorp.com> + + * configure: Regenerated. + * configure.ac: Add test for System V shared memory and semaphore. + * debug.c, debug.h: Add trace support for new devices. + * hw_sem.c, hw_shm.c: New files. + * Makefile.in: Add hw_sem.c and hw_shm.c. + 2008-07-11 Hans-Peter Nilsson <hp@axis.com> * configure.ac: Add test for libz and zlib.h. diff --git a/sim/ppc/Makefile.in b/sim/ppc/Makefile.in index 86fc8e62..911bed4 100644 --- a/sim/ppc/Makefile.in +++ b/sim/ppc/Makefile.in @@ -843,6 +843,8 @@ hw_opic.o: hw_opic.c $(DEVICE_TABLE_H) hw_pal.o: hw_pal.c $(DEVICE_TABLE_H) $(CPU_H) hw_phb.o: hw_phb.c $(DEVICE_TABLE_H) $(HW_PHB_H) $(COREFILE_H) hw_register.o: hw_register.c $(DEVICE_TABLE_H) $(PSIM_H) +hw_sem.o: hw_sem.c $(DEVICE_TABLE_H) $(PSIM_H) +hw_shm.o: hw_shm.c $(DEVICE_TABLE_H) $(PSIM_H) hw_trace.o: hw_trace.c $(DEVICE_TABLE_H) hw_vm.o: hw_vm.c $(DEVICE_TABLE_H) $(CPU_H) # ignore this line, it stops make from getting confused diff --git a/sim/ppc/configure b/sim/ppc/configure index e96bf3b..6ac9104 100755 --- a/sim/ppc/configure +++ b/sim/ppc/configure @@ -2715,10 +2715,263 @@ esac fi; +echo "$as_me:$LINENO: checking if union semun defined" >&5 +echo $ECHO_N "checking if union semun defined... $ECHO_C" >&6 +if test "${ac_cv_HAS_UNION_SEMUN+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/sem.h> +int +main () +{ +union semun arg ; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_has_union_semun="yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_has_union_semun="no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_cv_has_union_semun" >&5 +echo "${ECHO_T}$ac_cv_has_union_semun" >&6 + +fi +echo "$as_me:$LINENO: result: $ac_cv_HAS_UNION_SEMUN" >&5 +echo "${ECHO_T}$ac_cv_HAS_UNION_SEMUN" >&6 + + +if test "$ac_cv_has_union_semun" = "yes"; then + echo "$as_me:$LINENO: checking whether System V semaphores are supported" >&5 +echo $ECHO_N "checking whether System V semaphores are supported... $ECHO_C" >&6 +if test "${ac_cv_sysv_sem+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + #include <sys/types.h> + #include <sys/ipc.h> + #include <sys/sem.h> + int main () { + union semun arg ; + + int id=semget(IPC_PRIVATE,1,IPC_CREAT|0400); + if (id == -1) + exit(1); + arg.val = 0; /* avoid implicit type cast to union */ + if (semctl(id, 0, IPC_RMID, arg) == -1) + exit(1); + exit(0); + } + +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sysv_sem="yes" +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_sysv_sem="no" +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + +fi +echo "$as_me:$LINENO: result: $ac_cv_sysv_sem" >&5 +echo "${ECHO_T}$ac_cv_sysv_sem" >&6 +else # semun is not defined + echo "$as_me:$LINENO: checking whether System V semaphores are supported" >&5 +echo $ECHO_N "checking whether System V semaphores are supported... $ECHO_C" >&6 +if test "${ac_cv_sysv_sem+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + #include <sys/types.h> + #include <sys/ipc.h> + #include <sys/sem.h> + union semun { + int val; + struct semid_ds *buf; + ushort *array; + }; + int main () { + union semun arg ; + + int id=semget(IPC_PRIVATE,1,IPC_CREAT|0400); + if (id == -1) + exit(1); + arg.val = 0; /* avoid implicit type cast to union */ + if (semctl(id, 0, IPC_RMID, arg) == -1) + exit(1); + exit(0); + } + +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sysv_sem="yes" +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_sysv_sem="no" +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + +fi +echo "$as_me:$LINENO: result: $ac_cv_sysv_sem" >&5 +echo "${ECHO_T}$ac_cv_sysv_sem" >&6 +fi + +echo "$as_me:$LINENO: checking whether System V shared memory is supported" >&5 +echo $ECHO_N "checking whether System V shared memory is supported... $ECHO_C" >&6 +if test "${ac_cv_sysv_shm+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + +if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/shm.h> +int main () { + int id=shmget(IPC_PRIVATE,1,IPC_CREAT|0400); + if (id == -1) + exit(1); + if (shmctl(id, IPC_RMID, 0) == -1) + exit(1); + exit(0); +} + +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sysv_shm="yes" +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_sysv_shm="no" +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + +fi +echo "$as_me:$LINENO: result: $ac_cv_sysv_shm" >&5 +echo "${ECHO_T}$ac_cv_sysv_shm" >&6 + +if test x"$ac_cv_sysv_shm" = x"yes" -a x"$ac_cv_sysv_sem" = x"yes" ; then + sim_sysv_ipc_hw=",sem,shm"; +else + sim_sysv_ipc_hw=""; +fi + +if test x"$ac_cv_has_union_semun" = x"yes" -a x"$ac_cv_sysv_sem" = x"yes" ; then + sim_hwflags="-DHAS_UNION_SEMUN"; +fi + + # Check whether --enable-sim-hardware or --disable-sim-hardware was given. if test "${enable_sim_hardware+set}" = set; then enableval="$enable_sim_hardware" - hardware="cpu,memory,nvram,iobus,htab,disk,trace,register,vm,init,core,pal,com,eeprom,opic,glue,phb,ide" + hardware="cpu,memory,nvram,iobus,htab,disk,trace,register,vm,init,core,pal,com,eeprom,opic,glue,phb,ide${sim_sysv_ipc_hw}" case "${enableval}" in yes) ;; no) { { echo "$as_me:$LINENO: error: \"List of hardware must be specified for --enable-sim-hardware\"" >&5 @@ -2734,14 +2987,13 @@ if test x"$silent" != x"yes" && test x"$hardware" != x""; then echo "Setting hardware to $sim_hw_src, $sim_hw_obj" fi else - hardware="cpu,memory,nvram,iobus,htab,disk,trace,register,vm,init,core,pal,com,eeprom,opic,glue,phb,ide" + hardware="cpu,memory,nvram,iobus,htab,disk,trace,register,vm,init,core,pal,com,eeprom,opic,glue,phb,ide${sim_sysv_ipc_hw}" sim_hw_src=`echo $hardware | sed -e 's/,/.c hw_/g' -e 's/^/hw_/' -e s'/$/.c/'` sim_hw_obj=`echo $sim_hw_src | sed -e 's/\.c/.o/g'` if test x"$silent" != x"yes"; then echo "Setting hardware to $sim_hw_src, $sim_hw_obj" fi fi; - # Check whether --enable-sim-hostbitsize or --disable-sim-hostbitsize was given. if test "${enable_sim_hostbitsize+set}" = set; then enableval="$enable_sim_hostbitsize" @@ -2758,7 +3010,6 @@ else sim_hostbitsize="" fi; - # Check whether --enable-sim-hostendian or --disable-sim-hostendian was given. if test "${enable_sim_hostendian+set}" = set; then enableval="$enable_sim_hostendian" diff --git a/sim/ppc/configure.ac b/sim/ppc/configure.ac index 730091b..8a580c8 100644 --- a/sim/ppc/configure.ac +++ b/sim/ppc/configure.ac @@ -209,10 +209,105 @@ case "${target}" in esac ])dnl +AC_CACHE_CHECK([if union semun defined], + ac_cv_HAS_UNION_SEMUN, + [AC_TRY_COMPILE([ +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/sem.h>], +[union semun arg ;], +[ac_cv_has_union_semun="yes"], +[ac_cv_has_union_semun="no"]) +AC_MSG_RESULT($ac_cv_has_union_semun) +]) + + +if test "$ac_cv_has_union_semun" = "yes"; then + AC_CACHE_CHECK(whether System V semaphores are supported, + ac_cv_sysv_sem, + [ + AC_TRY_RUN( + [ + #include <sys/types.h> + #include <sys/ipc.h> + #include <sys/sem.h> + int main () { + union semun arg ; + + int id=semget(IPC_PRIVATE,1,IPC_CREAT|0400); + if (id == -1) + exit(1); + arg.val = 0; /* avoid implicit type cast to union */ + if (semctl(id, 0, IPC_RMID, arg) == -1) + exit(1); + exit(0); + } + ], + ac_cv_sysv_sem="yes", ac_cv_sysv_sem="no", :) + ]) +else # semun is not defined + AC_CACHE_CHECK(whether System V semaphores are supported, + ac_cv_sysv_sem, + [ + AC_TRY_RUN( + [ + #include <sys/types.h> + #include <sys/ipc.h> + #include <sys/sem.h> + union semun { + int val; + struct semid_ds *buf; + ushort *array; + }; + int main () { + union semun arg ; + + int id=semget(IPC_PRIVATE,1,IPC_CREAT|0400); + if (id == -1) + exit(1); + arg.val = 0; /* avoid implicit type cast to union */ + if (semctl(id, 0, IPC_RMID, arg) == -1) + exit(1); + exit(0); + } + ], + ac_cv_sysv_sem="yes", ac_cv_sysv_sem="no", :) + ]) +fi + +AC_CACHE_CHECK(whether System V shared memory is supported, +ac_cv_sysv_shm, +[ +AC_TRY_RUN([ +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/shm.h> +int main () { + int id=shmget(IPC_PRIVATE,1,IPC_CREAT|0400); + if (id == -1) + exit(1); + if (shmctl(id, IPC_RMID, 0) == -1) + exit(1); + exit(0); +} +], +ac_cv_sysv_shm="yes", ac_cv_sysv_shm="no", :) +]) + +if test x"$ac_cv_sysv_shm" = x"yes" -a x"$ac_cv_sysv_sem" = x"yes" ; then + sim_sysv_ipc_hw=",sem,shm"; +else + sim_sysv_ipc_hw=""; +fi + +if test x"$ac_cv_has_union_semun" = x"yes" -a x"$ac_cv_sysv_sem" = x"yes" ; then + sim_hwflags="-DHAS_UNION_SEMUN"; +fi + AC_ARG_ENABLE(sim-hardware, [ --enable-sim-hardware=list Specify the hardware to be included in the build.], -[hardware="cpu,memory,nvram,iobus,htab,disk,trace,register,vm,init,core,pal,com,eeprom,opic,glue,phb,ide" +[hardware="cpu,memory,nvram,iobus,htab,disk,trace,register,vm,init,core,pal,com,eeprom,opic,glue,phb,ide${sim_sysv_ipc_hw}" case "${enableval}" in yes) ;; no) AC_MSG_ERROR("List of hardware must be specified for --enable-sim-hardware"); hardware="";; @@ -224,14 +319,13 @@ sim_hw_src=`echo $hardware | sed -e 's/,/.c hw_/g' -e 's/^/hw_/' -e s'/$/.c/'` sim_hw_obj=`echo $sim_hw_src | sed -e 's/\.c/.o/g'` if test x"$silent" != x"yes" && test x"$hardware" != x""; then echo "Setting hardware to $sim_hw_src, $sim_hw_obj" -fi],[hardware="cpu,memory,nvram,iobus,htab,disk,trace,register,vm,init,core,pal,com,eeprom,opic,glue,phb,ide" +fi],[hardware="cpu,memory,nvram,iobus,htab,disk,trace,register,vm,init,core,pal,com,eeprom,opic,glue,phb,ide${sim_sysv_ipc_hw}" sim_hw_src=`echo $hardware | sed -e 's/,/.c hw_/g' -e 's/^/hw_/' -e s'/$/.c/'` sim_hw_obj=`echo $sim_hw_src | sed -e 's/\.c/.o/g'` if test x"$silent" != x"yes"; then echo "Setting hardware to $sim_hw_src, $sim_hw_obj" fi])dnl - AC_ARG_ENABLE(sim-hostbitsize, [ --enable-sim-hostbitsize=32|64 Specify host bitsize (32 or 64).], [case "${enableval}" in diff --git a/sim/ppc/debug.c b/sim/ppc/debug.c index 5931d1e..79dd47b 100644 --- a/sim/ppc/debug.c +++ b/sim/ppc/debug.c @@ -28,6 +28,9 @@ #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif int ppc_trace[nr_trace_options]; @@ -70,6 +73,8 @@ static trace_option_descriptor trace_description[] = { { trace_pass_device, "pass-device" }, { trace_phb_device, "phb-device" }, { trace_register_device, "register-device", "Device initializing registers" }, + { trace_sem_device, "sem-device" }, + { trace_shm_device, "shm-device" }, { trace_stack_device, "stack-device" }, { trace_vm_device, "vm-device" }, /* packages */ diff --git a/sim/ppc/debug.h b/sim/ppc/debug.h index 1fdb36e..e49b795 100644 --- a/sim/ppc/debug.h +++ b/sim/ppc/debug.h @@ -51,6 +51,8 @@ typedef enum { trace_pal_device, trace_pass_device, trace_phb_device, + trace_sem_device, + trace_shm_device, trace_stack_device, trace_register_device, trace_vm_device, diff --git a/sim/ppc/hw_sem.c b/sim/ppc/hw_sem.c new file mode 100644 index 0000000..28e0c17 --- /dev/null +++ b/sim/ppc/hw_sem.c @@ -0,0 +1,289 @@ +/* This file is part of the program psim. + + Copyright (C) 1997,2008, Joel Sherrill <joel@OARcorp.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _HW_SEM_C_ +#define _HW_SEM_C_ + +#include "device_table.h" + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +#include <sys/ipc.h> +#include <sys/sem.h> + +#include <errno.h> + +/* DEVICE + + + sem - provide access to a unix semaphore + + + DESCRIPTION + + + This device implements an interface to a unix semaphore. + + + PROPERTIES + + + reg = <address> <size> (required) + + Determine where the memory lives in the parents address space. + + key = <integer> (required) + + This is the key of the unix semaphore. + + EXAMPLES + + + Enable tracing of the sem: + + | bash$ psim -t sem-device \ + + + Configure a UNIX semaphore using key 0x12345678 mapped into psim + address space at 0xfff00000: + + | -o '/sem@0xfff00000/reg 0xfff00000 0x80000' \ + | -o '/sem@0xfff00000/key 0x12345678' \ + + sim/ppc/run -o '/#address-cells 1' \ + -o '/sem@0xfff00000/reg 0xfff00000 12' \ + -o '/sem@0xfff00000/key 0x12345678' ../psim-hello/hello + + REGISTERS + + offset 0 - lock count + offset 4 - lock operation + offset 8 - unlock operation + + All reads return the current or resulting count. + + BUGS + + None known. + + */ + +typedef struct _hw_sem_device { + unsigned_word physical_address; + key_t key; + int id; + int initial; + int count; +} hw_sem_device; + +#if !HAS_UNION_SEMUN +union semun { + int val; + struct semid_ds *buf; + unsigned short int *array; +#if defined(__linux__) + struct seminfo *__buf; +#endif +}; +#endif + +static void +hw_sem_init_data(device *me) +{ + hw_sem_device *sem = (hw_sem_device*)device_data(me); + const device_unit *d; + int status; + union semun help; + + /* initialize the properties of the sem */ + + if (device_find_property(me, "key") == NULL) + error("sem_init_data() required key property is missing\n"); + + if (device_find_property(me, "value") == NULL) + error("sem_init_data() required value property is missing\n"); + + sem->key = (key_t) device_find_integer_property(me, "key"); + DTRACE(sem, ("semaphore key (%d)\n", sem->key) ); + + sem->initial = (int) device_find_integer_property(me, "value"); + DTRACE(sem, ("semaphore initial value (%d)\n", sem->initial) ); + + d = device_unit_address(me); + sem->physical_address = d->cells[ d->nr_cells-1 ]; + DTRACE(sem, ("semaphore physical_address=0x%x\n", sem->physical_address)); + + /* Now to initialize the semaphore */ + + if ( sem->initial != -1 ) { + + sem->id = semget(sem->key, 1, IPC_CREAT | 0660); + if (sem->id == -1) + error("hw_sem_init_data() semget failed\n"); + + help.val = sem->initial; + status = semctl( sem->id, 0, SETVAL, help ); + if (status == -1) + error("hw_sem_init_data() semctl -- set value failed\n"); + + } else { + sem->id = semget(sem->key, 1, 0660); + if (sem->id == -1) + error("hw_sem_init_data() semget failed\n"); + } + + sem->count = semctl( sem->id, 0, GETVAL, help ); + if (sem->count == -1) + error("hw_sem_init_data() semctl -- get value failed\n"); + DTRACE(sem, ("semaphore OS value (%d)\n", sem->count) ); +} + +static void +hw_sem_attach_address_callback(device *me, + attach_type attach, + int space, + unsigned_word addr, + unsigned nr_bytes, + access_type access, + device *client) /*callback/default*/ +{ + hw_sem_device *sem = (hw_sem_device*)device_data(me); + + if (space != 0) + error("sem_attach_address_callback() invalid address space\n"); + + if (nr_bytes == 12) + error("sem_attach_address_callback() invalid size\n"); + + sem->physical_address = addr; + DTRACE(sem, ("semaphore physical_address=0x%x\n", addr)); +} + +static unsigned +hw_sem_io_read_buffer(device *me, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes, + cpu *processor, + unsigned_word cia) +{ + hw_sem_device *sem = (hw_sem_device*)device_data(me); + struct sembuf sb; + int status; + unsigned32 u32; + union semun help; + + /* do we need to worry about out of range addresses? */ + + DTRACE(sem, ("semaphore read addr=0x%x length=%d\n", addr, nr_bytes)); + + if (!(addr >= sem->physical_address && addr <= sem->physical_address + 11)) + error("hw_sem_io_read_buffer() invalid address - out of range\n"); + + if ((addr % 4) != 0) + error("hw_sem_io_read_buffer() invalid address - alignment\n"); + + if (nr_bytes != 4) + error("hw_sem_io_read_buffer() invalid length\n"); + + switch ( (addr - sem->physical_address) / 4 ) { + + case 0: /* OBTAIN CURRENT VALUE */ + break; + + case 1: /* LOCK */ + sb.sem_num = 0; + sb.sem_op = -1; + sb.sem_flg = 0; + + status = semop(sem->id, &sb, 1); + if (status == -1) { + perror( "hw_sem.c: lock" ); + error("hw_sem_io_read_buffer() sem lock\n"); + } + + DTRACE(sem, ("semaphore lock %d\n", sem->count)); + break; + + case 2: /* UNLOCK */ + sb.sem_num = 0; + sb.sem_op = 1; + sb.sem_flg = 0; + + status = semop(sem->id, &sb, 1); + if (status == -1) { + perror( "hw_sem.c: unlock" ); + error("hw_sem_io_read_buffer() sem unlock\n"); + } + DTRACE(sem, ("semaphore unlock %d\n", sem->count)); + break; + + default: + error("hw_sem_io_read_buffer() invalid address - unknown error\n"); + break; + } + + /* assume target is big endian */ + u32 = H2T_4(semctl( sem->id, 0, GETVAL, help )); + + DTRACE(sem, ("semaphore OS value (%d)\n", u32) ); + if (u32 == 0xffffffff) { + perror( "hw_sem.c: getval" ); + error("hw_sem_io_read_buffer() semctl -- get value failed\n"); + } + + memcpy(dest, &u32, nr_bytes); + return nr_bytes; + +} + +static device_callbacks const hw_sem_callbacks = { + { generic_device_init_address, hw_sem_init_data }, + { hw_sem_attach_address_callback, }, /* address */ + { hw_sem_io_read_buffer, NULL }, /* IO */ + { NULL, }, /* DMA */ + { NULL, }, /* interrupt */ + { NULL, }, /* unit */ + NULL, +}; + +static void * +hw_sem_create(const char *name, + const device_unit *unit_address, + const char *args) +{ + hw_sem_device *sem = ZALLOC(hw_sem_device); + return sem; +} + +const device_descriptor hw_sem_device_descriptor[] = { + { "sem", hw_sem_create, &hw_sem_callbacks }, + { NULL }, +}; + +#endif /* _HW_SEM_C_ */ diff --git a/sim/ppc/hw_shm.c b/sim/ppc/hw_shm.c new file mode 100644 index 0000000..01a4a9a --- /dev/null +++ b/sim/ppc/hw_shm.c @@ -0,0 +1,236 @@ +/* This file is part of the program psim. + + Copyright (C) 1997,2008, Joel Sherrill <joel@OARcorp.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _HW_SHM_C_ +#define _HW_SHM_C_ + +#include "device_table.h" + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +#include <sys/ipc.h> +#include <sys/shm.h> + + +/* DEVICE + + + shm - map unix shared memory into psim address space + + + DESCRIPTION + + + This device implements an area of memory which is mapped into UNIX + shared memory. + + + PROPERTIES + + + reg = <address> <size> (required) + + Determine where the memory lives in the parents address space. + The SHM area is assumed to be of the same length. + + key = <integer> (required) + + This is the key of the unix shared memory area. + + EXAMPLES + + + Enable tracing of the shm: + + | bash$ psim -t shm-device \ + + + Configure a 512 kilobytes of UNIX shared memory with the key 0x12345678 + mapped into psim address space at 0x0c000000. + + | -o '/shm@0x0c000000/reg 0x0c000000 0x80000' \ + | -o '/shm@0x0c000000/key 0x12345678' \ + + sim/ppc/run -o '/#address-cells 1' \ + -o '/shm@0x0c000000/reg 0x0c000000 0x80000' \ + -o '/shm@0x0c000000/key 0x12345678' ../psim-hello/hello + + BUGS + + None known. + + */ + +typedef struct _hw_shm_device { + unsigned_word physical_address; + char *shm_address; + unsigned sizeof_memory; + key_t key; + int id; +} hw_shm_device; + +static void +hw_shm_init_data(device *me) +{ + hw_shm_device *shm = (hw_shm_device*)device_data(me); + const device_unit *d; + reg_property_spec reg; + int i; + + /* Obtain the Key Value */ + if (device_find_property(me, "key") == NULL) + error("shm_init_data() required key property is missing\n"); + + shm->key = (key_t) device_find_integer_property(me, "key"); + DTRACE(shm, ("shm key (0x%08x)\n", shm->key) ); + + /* Figure out where this memory is in address space and how long it is */ + if ( !device_find_reg_array_property(me, "reg", 0, ®) ) + error("hw_shm_init_data() no address registered\n"); + + /* Determine the address and length being as paranoid as possible */ + shm->physical_address = 0xffffffff; + shm->sizeof_memory = 0xffffffff; + + for ( i=0 ; i<reg.address.nr_cells; i++ ) { + if (reg.address.cells[0] == 0 && reg.size.cells[0] == 0) + continue; + + if ( shm->physical_address != 0xffffffff ) + device_error(me, "Only single celled address ranges supported\n"); + + shm->physical_address = reg.address.cells[i]; + DTRACE(shm, ("shm physical_address=0x%x\n", shm->physical_address)); + + shm->sizeof_memory = reg.size.cells[i]; + DTRACE(shm, ("shm length=0x%x\n", shm->sizeof_memory)); + } + + if ( shm->physical_address == 0xffffffff ) + device_error(me, "Address not specified\n" ); + + if ( shm->sizeof_memory == 0xffffffff ) + device_error(me, "Length not specified\n" ); + + /* Now actually attach to or create the shared memory area */ + shm->id = shmget(shm->key, shm->sizeof_memory, IPC_CREAT | 0660); + if (shm->id == -1) + error("hw_shm_init_data() shmget failed\n"); + + shm->shm_address = shmat(shm->id, (char *)0, SHM_RND); + if (shm->shm_address == (void *)-1) + error("hw_shm_init_data() shmat failed\n"); +} + +static void +hw_shm_attach_address_callback(device *me, + attach_type attach, + int space, + unsigned_word addr, + unsigned nr_bytes, + access_type access, + device *client) /*callback/default*/ +{ + hw_shm_device *shm = (hw_shm_device*)device_data(me); + + if (space != 0) + error("shm_attach_address_callback() invalid address space\n"); + + if (nr_bytes == 0) + error("shm_attach_address_callback() invalid size\n"); +} + + +static unsigned +hw_shm_io_read_buffer(device *me, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes, + cpu *processor, + unsigned_word cia) +{ + hw_shm_device *shm = (hw_shm_device*)device_data(me); + + /* do we need to worry about out of range addresses? */ + + DTRACE(shm, ("read %p %x %x %x\n", \ + shm->shm_address, shm->physical_address, addr, nr_bytes) ); + + memcpy(dest, &shm->shm_address[addr - shm->physical_address], nr_bytes); + return nr_bytes; +} + + +static unsigned +hw_shm_io_write_buffer(device *me, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes, + cpu *processor, + unsigned_word cia) +{ + hw_shm_device *shm = (hw_shm_device*)device_data(me); + + /* do we need to worry about out of range addresses? */ + + DTRACE(shm, ("write %p %x %x %x\n", \ + shm->shm_address, shm->physical_address, addr, nr_bytes) ); + + memcpy(&shm->shm_address[addr - shm->physical_address], source, nr_bytes); + return nr_bytes; +} + +static device_callbacks const hw_shm_callbacks = { + { generic_device_init_address, hw_shm_init_data }, + { hw_shm_attach_address_callback, }, /* address */ + { hw_shm_io_read_buffer, + hw_shm_io_write_buffer }, /* IO */ + { NULL, }, /* DMA */ + { NULL, }, /* interrupt */ + { NULL, }, /* unit */ + NULL, +}; + +static void * +hw_shm_create(const char *name, + const device_unit *unit_address, + const char *args) +{ + hw_shm_device *shm = ZALLOC(hw_shm_device); + return shm; +} + + + +const device_descriptor hw_shm_device_descriptor[] = { + { "shm", hw_shm_create, &hw_shm_callbacks }, + { NULL }, +}; + +#endif /* _HW_SHM_C_ */ |