]> Git Repo - binutils.git/blob - sim/ppc/hw_sem.c
Automatic date update in version.in
[binutils.git] / sim / ppc / hw_sem.c
1 /*  This file is part of the program psim.
2
3     Copyright (C) 1997,2008, Joel Sherrill <[email protected]>
4
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.
9
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.
14  
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/>.
17  
18     */
19
20
21 #ifndef _HW_SEM_C_
22 #define _HW_SEM_C_
23
24 #include "device_table.h"
25
26 #include <string.h>
27 #include <sys/ipc.h>
28 #include <sys/sem.h>
29
30 #include <errno.h>
31
32 /* DEVICE
33
34
35    sem - provide access to a unix semaphore
36
37
38    DESCRIPTION
39
40
41    This device implements an interface to a unix semaphore.
42
43
44    PROPERTIES
45
46
47    reg = <address> <size> (required)
48
49    Determine where the memory lives in the parents address space.
50
51    key = <integer> (required)
52
53    This is the key of the unix semaphore.
54
55    EXAMPLES
56
57
58    Enable tracing of the sem:
59
60    |  bash$ psim -t sem-device \
61
62
63    Configure a UNIX semaphore using key 0x12345678 mapped into psim
64    address space at 0xfff00000:
65
66    |  -o '/sem@0xfff00000/reg 0xfff00000 0x80000' \
67    |  -o '/sem@0xfff00000/key 0x12345678' \
68
69    sim/ppc/run -o '/#address-cells 1' \
70          -o '/sem@0xfff00000/reg 0xfff00000 12' \
71          -o '/sem@0xfff00000/key 0x12345678' ../psim-hello/hello
72
73    REGISTERS
74
75    offset 0 - lock count
76    offset 4 - lock operation
77    offset 8 - unlock operation
78
79    All reads return the current or resulting count.
80
81    BUGS
82
83    None known.
84
85    */
86
87 typedef struct _hw_sem_device {
88   unsigned_word physical_address;
89   key_t key;
90   int id;
91   int initial;
92   int count;
93 } hw_sem_device;
94
95 #ifndef HAVE_UNION_SEMUN
96 union semun {
97   int val;
98   struct semid_ds *buf;
99   unsigned short int *array;
100 #if defined(__linux__)
101   struct seminfo *__buf;
102 #endif
103 };
104 #endif
105
106 static void
107 hw_sem_init_data(device *me)
108 {
109   hw_sem_device *sem = (hw_sem_device*)device_data(me);
110   const device_unit *d;
111   int status;
112   union semun help;
113
114   /* initialize the properties of the sem */
115
116   if (device_find_property(me, "key") == NULL)
117     error("sem_init_data() required key property is missing\n");
118
119   if (device_find_property(me, "value") == NULL)
120     error("sem_init_data() required value property is missing\n");
121
122   sem->key = (key_t) device_find_integer_property(me, "key");
123   DTRACE(sem, ("semaphore key (%d)\n", sem->key) );
124
125   sem->initial = (int) device_find_integer_property(me, "value");
126   DTRACE(sem, ("semaphore initial value (%d)\n", sem->initial) );
127
128   d = device_unit_address(me);
129   sem->physical_address = d->cells[ d->nr_cells-1 ];
130   DTRACE(sem, ("semaphore physical_address=0x%x\n", sem->physical_address));
131
132   /* Now to initialize the semaphore */
133
134   if ( sem->initial != -1 ) {
135
136     sem->id = semget(sem->key, 1, IPC_CREAT | 0660);
137     if (sem->id == -1)
138       error("hw_sem_init_data() semget failed\n");
139
140     help.val = sem->initial;
141     status = semctl( sem->id, 0, SETVAL, help );
142     if (status == -1)
143       error("hw_sem_init_data() semctl -- set value failed\n");
144
145   } else {
146     sem->id = semget(sem->key, 1, 0660);
147     if (sem->id == -1)
148       error("hw_sem_init_data() semget failed\n");
149   }
150
151   sem->count = semctl( sem->id, 0, GETVAL, help );
152   if (sem->count == -1)
153     error("hw_sem_init_data() semctl -- get value failed\n");
154   DTRACE(sem, ("semaphore OS value (%d)\n", sem->count) );
155 }
156
157 static void
158 hw_sem_attach_address_callback(device *me,
159                                 attach_type attach,
160                                 int space,
161                                 unsigned_word addr,
162                                 unsigned nr_bytes,
163                                 access_type access,
164                                 device *client) /*callback/default*/
165 {
166   hw_sem_device *sem = (hw_sem_device*)device_data(me);
167
168   if (space != 0)
169     error("sem_attach_address_callback() invalid address space\n");
170
171   if (nr_bytes == 12)
172     error("sem_attach_address_callback() invalid size\n");
173
174   sem->physical_address = addr;
175   DTRACE(sem, ("semaphore physical_address=0x%x\n", addr));
176 }
177
178 static unsigned
179 hw_sem_io_read_buffer(device *me,
180                          void *dest,
181                          int space,
182                          unsigned_word addr,
183                          unsigned nr_bytes,
184                          cpu *processor,
185                          unsigned_word cia)
186 {
187   hw_sem_device *sem = (hw_sem_device*)device_data(me);
188   struct sembuf sb;
189   int status;
190   uint32_t u32;
191   union semun help;
192
193   /* do we need to worry about out of range addresses? */
194
195   DTRACE(sem, ("semaphore read addr=0x%x length=%d\n", addr, nr_bytes));
196
197   if (!(addr >= sem->physical_address && addr <= sem->physical_address + 11))
198     error("hw_sem_io_read_buffer() invalid address - out of range\n");
199
200   if ((addr % 4) != 0)
201     error("hw_sem_io_read_buffer() invalid address - alignment\n");
202
203   if (nr_bytes != 4)
204     error("hw_sem_io_read_buffer() invalid length\n");
205
206   switch ( (addr - sem->physical_address) / 4 ) {
207
208     case 0:  /* OBTAIN CURRENT VALUE */
209       break; 
210
211     case 1:  /* LOCK */
212       sb.sem_num = 0;
213       sb.sem_op  = -1;
214       sb.sem_flg = 0;
215
216       status = semop(sem->id, &sb, 1);
217       if (status == -1) {
218         perror( "hw_sem.c: lock" );
219         error("hw_sem_io_read_buffer() sem lock\n");
220       }
221
222       DTRACE(sem, ("semaphore lock %d\n", sem->count));
223       break; 
224
225     case 2: /* UNLOCK */
226       sb.sem_num = 0;
227       sb.sem_op  = 1;
228       sb.sem_flg = 0;
229
230       status = semop(sem->id, &sb, 1);
231       if (status == -1) {
232         perror( "hw_sem.c: unlock" );
233         error("hw_sem_io_read_buffer() sem unlock\n");
234       }
235       DTRACE(sem, ("semaphore unlock %d\n", sem->count));
236       break; 
237
238     default:
239       error("hw_sem_io_read_buffer() invalid address - unknown error\n");
240       break; 
241   }
242
243   /* assume target is big endian */
244   u32 = H2T_4(semctl( sem->id, 0, GETVAL, help ));
245
246   DTRACE(sem, ("semaphore OS value (%d)\n", u32) );
247   if (u32 == 0xffffffff) {
248     perror( "hw_sem.c: getval" );
249     error("hw_sem_io_read_buffer() semctl -- get value failed\n");
250   }
251
252   memcpy(dest, &u32, nr_bytes);
253   return nr_bytes;
254
255 }
256
257 static device_callbacks const hw_sem_callbacks = {
258   { generic_device_init_address, hw_sem_init_data },
259   { hw_sem_attach_address_callback, }, /* address */
260   { hw_sem_io_read_buffer, NULL }, /* IO */
261   { NULL, }, /* DMA */
262   { NULL, }, /* interrupt */
263   { NULL, }, /* unit */
264   NULL,
265 };
266
267 static void *
268 hw_sem_create(const char *name,
269                  const device_unit *unit_address,
270                  const char *args)
271 {
272   hw_sem_device *sem = ZALLOC(hw_sem_device);
273   return sem;
274 }
275
276 const device_descriptor hw_sem_device_descriptor[] = {
277   { "sem", hw_sem_create, &hw_sem_callbacks },
278   { NULL },
279 };
280
281 #endif /* _HW_SEM_C_ */
This page took 0.03956 seconds and 4 git commands to generate.