diff options
author | Joel Sherrill <joel.sherrill@oarcorp.com> | 2008-11-18 21:30:37 +0000 |
---|---|---|
committer | Joel Sherrill <joel.sherrill@oarcorp.com> | 2008-11-18 21:30:37 +0000 |
commit | 00a0b122cf3b524243c3cea05101bacd5a1595ba (patch) | |
tree | ae53946a87294331d26ad6f53352322c14a4f60b /sim/ppc/hw_sem.c | |
parent | 394a666683b04e52d011fdc548b2bc5e60091693 (diff) | |
download | gdb-00a0b122cf3b524243c3cea05101bacd5a1595ba.zip gdb-00a0b122cf3b524243c3cea05101bacd5a1595ba.tar.gz gdb-00a0b122cf3b524243c3cea05101bacd5a1595ba.tar.bz2 |
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.
Diffstat (limited to 'sim/ppc/hw_sem.c')
-rw-r--r-- | sim/ppc/hw_sem.c | 289 |
1 files changed, 289 insertions, 0 deletions
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_ */ |