Add translations for various sub-directories
[binutils-gdb.git] / sim / ppc / hw_sem.c
blob9495b8591b92db4f519cc215ed52c9b297eeac1b
1 /* This file is part of the program psim.
3 Copyright (C) 1997,2008, Joel Sherrill <joel@OARcorp.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #ifndef _HW_SEM_C_
22 #define _HW_SEM_C_
24 #include "device_table.h"
26 #include <string.h>
27 #include <sys/ipc.h>
28 #include <sys/sem.h>
30 #include <errno.h>
32 /* DEVICE
35 sem - provide access to a unix semaphore
38 DESCRIPTION
41 This device implements an interface to a unix semaphore.
44 PROPERTIES
47 reg = <address> <size> (required)
49 Determine where the memory lives in the parents address space.
51 key = <integer> (required)
53 This is the key of the unix semaphore.
55 EXAMPLES
58 Enable tracing of the sem:
60 | bash$ psim -t sem-device \
63 Configure a UNIX semaphore using key 0x12345678 mapped into psim
64 address space at 0xfff00000:
66 | -o '/sem@0xfff00000/reg 0xfff00000 0x80000' \
67 | -o '/sem@0xfff00000/key 0x12345678' \
69 sim/ppc/run -o '/#address-cells 1' \
70 -o '/sem@0xfff00000/reg 0xfff00000 12' \
71 -o '/sem@0xfff00000/key 0x12345678' ../psim-hello/hello
73 REGISTERS
75 offset 0 - lock count
76 offset 4 - lock operation
77 offset 8 - unlock operation
79 All reads return the current or resulting count.
81 BUGS
83 None known.
87 #ifdef HAVE_SYSV_SEM
89 typedef struct _hw_sem_device {
90 unsigned_word physical_address;
91 key_t key;
92 int id;
93 int initial;
94 int count;
95 } hw_sem_device;
97 #ifndef HAVE_UNION_SEMUN
98 union semun {
99 int val;
100 struct semid_ds *buf;
101 unsigned short int *array;
102 #if defined(__linux__)
103 struct seminfo *__buf;
104 #endif
106 #endif
108 static void
109 hw_sem_init_data(device *me)
111 hw_sem_device *sem = (hw_sem_device*)device_data(me);
112 const device_unit *d;
113 int status;
114 union semun help = {};
116 /* initialize the properties of the sem */
118 if (device_find_property(me, "key") == NULL)
119 error("sem_init_data() required key property is missing\n");
121 if (device_find_property(me, "value") == NULL)
122 error("sem_init_data() required value property is missing\n");
124 sem->key = (key_t) device_find_integer_property(me, "key");
125 DTRACE(sem, ("semaphore key (%d)\n", sem->key) );
127 sem->initial = (int) device_find_integer_property(me, "value");
128 DTRACE(sem, ("semaphore initial value (%d)\n", sem->initial) );
130 d = device_unit_address(me);
131 sem->physical_address = d->cells[ d->nr_cells-1 ];
132 DTRACE(sem, ("semaphore physical_address=0x%x\n", sem->physical_address));
134 /* Now to initialize the semaphore */
136 if ( sem->initial != -1 ) {
138 sem->id = semget(sem->key, 1, IPC_CREAT | 0660);
139 if (sem->id == -1)
140 error("hw_sem_init_data() semget failed\n");
142 help.val = sem->initial;
143 status = semctl( sem->id, 0, SETVAL, help );
144 if (status == -1)
145 error("hw_sem_init_data() semctl -- set value failed\n");
147 } else {
148 sem->id = semget(sem->key, 1, 0660);
149 if (sem->id == -1)
150 error("hw_sem_init_data() semget failed\n");
153 sem->count = semctl( sem->id, 0, GETVAL, help );
154 if (sem->count == -1)
155 error("hw_sem_init_data() semctl -- get value failed\n");
156 DTRACE(sem, ("semaphore OS value (%d)\n", sem->count) );
159 static void
160 hw_sem_attach_address_callback(device *me,
161 attach_type attach,
162 int space,
163 unsigned_word addr,
164 unsigned nr_bytes,
165 access_type access,
166 device *client) /*callback/default*/
168 hw_sem_device *sem = (hw_sem_device*)device_data(me);
170 if (space != 0)
171 error("sem_attach_address_callback() invalid address space\n");
173 if (nr_bytes == 12)
174 error("sem_attach_address_callback() invalid size\n");
176 sem->physical_address = addr;
177 DTRACE(sem, ("semaphore physical_address=0x%x\n", addr));
180 static unsigned
181 hw_sem_io_read_buffer(device *me,
182 void *dest,
183 int space,
184 unsigned_word addr,
185 unsigned nr_bytes,
186 cpu *processor,
187 unsigned_word cia)
189 hw_sem_device *sem = (hw_sem_device*)device_data(me);
190 struct sembuf sb;
191 int status;
192 uint32_t u32;
193 union semun help = {};
195 /* do we need to worry about out of range addresses? */
197 DTRACE(sem, ("semaphore read addr=0x%x length=%d\n", addr, nr_bytes));
199 if (!(addr >= sem->physical_address && addr <= sem->physical_address + 11))
200 error("hw_sem_io_read_buffer() invalid address - out of range\n");
202 if ((addr % 4) != 0)
203 error("hw_sem_io_read_buffer() invalid address - alignment\n");
205 if (nr_bytes != 4)
206 error("hw_sem_io_read_buffer() invalid length\n");
208 switch ( (addr - sem->physical_address) / 4 ) {
210 case 0: /* OBTAIN CURRENT VALUE */
211 break;
213 case 1: /* LOCK */
214 sb.sem_num = 0;
215 sb.sem_op = -1;
216 sb.sem_flg = 0;
218 status = semop(sem->id, &sb, 1);
219 if (status == -1) {
220 perror( "hw_sem.c: lock" );
221 error("hw_sem_io_read_buffer() sem lock\n");
224 DTRACE(sem, ("semaphore lock %d\n", sem->count));
225 break;
227 case 2: /* UNLOCK */
228 sb.sem_num = 0;
229 sb.sem_op = 1;
230 sb.sem_flg = 0;
232 status = semop(sem->id, &sb, 1);
233 if (status == -1) {
234 perror( "hw_sem.c: unlock" );
235 error("hw_sem_io_read_buffer() sem unlock\n");
237 DTRACE(sem, ("semaphore unlock %d\n", sem->count));
238 break;
240 default:
241 error("hw_sem_io_read_buffer() invalid address - unknown error\n");
242 break;
245 /* assume target is big endian */
246 u32 = H2T_4(semctl( sem->id, 0, GETVAL, help ));
248 DTRACE(sem, ("semaphore OS value (%d)\n", u32) );
249 if (u32 == 0xffffffff) {
250 perror( "hw_sem.c: getval" );
251 error("hw_sem_io_read_buffer() semctl -- get value failed\n");
254 memcpy(dest, &u32, nr_bytes);
255 return nr_bytes;
259 static device_callbacks const hw_sem_callbacks = {
260 { generic_device_init_address, hw_sem_init_data },
261 { hw_sem_attach_address_callback, }, /* address */
262 { hw_sem_io_read_buffer, NULL }, /* IO */
263 { NULL, }, /* DMA */
264 { NULL, }, /* interrupt */
265 { NULL, }, /* unit */
266 NULL,
269 static void *
270 hw_sem_create(const char *name,
271 const device_unit *unit_address,
272 const char *args)
274 hw_sem_device *sem = ZALLOC(hw_sem_device);
275 return sem;
278 const device_descriptor hw_sem_device_descriptor[] = {
279 { "sem", hw_sem_create, &hw_sem_callbacks },
280 { NULL },
283 #else
285 const device_descriptor hw_sem_device_descriptor[] = {
286 { NULL },
289 #endif /* HAVE_SYSV_SEM */
291 #endif /* _HW_SEM_C_ */