PowerPC64 ld segfault with code in non-executable sections
[external/binutils.git] / sim / ppc / hw_shm.c
1 /*  This file is part of the program psim.
2
3     Copyright (C) 1997,2008, Joel Sherrill <joel@OARcorp.com>
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_SHM_C_
22 #define _HW_SHM_C_
23
24 #include "device_table.h"
25
26 #ifdef HAVE_STRING_H
27 #include <string.h>
28 #else
29 #ifdef HAVE_STRINGS_H
30 #include <strings.h>
31 #endif
32 #endif
33
34 #include <sys/ipc.h>
35 #include <sys/shm.h>
36
37
38 /* DEVICE
39
40
41    shm - map unix shared memory into psim address space
42
43
44    DESCRIPTION
45
46
47    This device implements an area of memory which is mapped into UNIX
48    shared memory.
49
50
51    PROPERTIES
52
53
54    reg = <address> <size> (required)
55
56    Determine where the memory lives in the parents address space.
57    The SHM area is assumed to be of the same length.
58
59    key = <integer> (required)
60
61    This is the key of the unix shared memory area.
62
63    EXAMPLES
64
65
66    Enable tracing of the shm:
67
68    |  bash$ psim -t shm-device \
69
70
71    Configure a 512 kilobytes of UNIX shared memory with the key 0x12345678
72    mapped into psim address space at 0x0c000000.
73
74    |  -o '/shm@0x0c000000/reg 0x0c000000 0x80000' \
75    |  -o '/shm@0x0c000000/key 0x12345678' \
76
77    sim/ppc/run -o '/#address-cells 1' \
78          -o '/shm@0x0c000000/reg 0x0c000000 0x80000' \
79          -o '/shm@0x0c000000/key 0x12345678' ../psim-hello/hello
80
81    BUGS
82
83    None known.
84
85    */
86
87 typedef struct _hw_shm_device {
88   unsigned_word physical_address;
89   char *shm_address;
90   unsigned sizeof_memory;
91   key_t key;
92   int id;
93 } hw_shm_device;
94
95 static void
96 hw_shm_init_data(device *me)
97 {
98   hw_shm_device *shm = (hw_shm_device*)device_data(me);
99   const device_unit *d;
100   reg_property_spec reg;
101   int i;
102
103   /* Obtain the Key Value */
104   if (device_find_property(me, "key") == NULL)
105     error("shm_init_data() required key property is missing\n");
106
107   shm->key = (key_t) device_find_integer_property(me, "key");
108   DTRACE(shm, ("shm key (0x%08x)\n", shm->key) );
109   
110   /* Figure out where this memory is in address space and how long it is */
111   if ( !device_find_reg_array_property(me, "reg", 0, &reg) )
112     error("hw_shm_init_data() no address registered\n");
113
114   /* Determine the address and length being as paranoid as possible */
115   shm->physical_address = 0xffffffff;
116   shm->sizeof_memory = 0xffffffff;
117
118   for ( i=0 ; i<reg.address.nr_cells; i++ ) {
119     if (reg.address.cells[0] == 0 && reg.size.cells[0] == 0)
120       continue;
121
122     if ( shm->physical_address != 0xffffffff )
123       device_error(me, "Only single celled address ranges supported\n");
124
125     shm->physical_address = reg.address.cells[i];
126     DTRACE(shm, ("shm physical_address=0x%x\n", shm->physical_address));
127
128     shm->sizeof_memory = reg.size.cells[i];
129     DTRACE(shm, ("shm length=0x%x\n", shm->sizeof_memory));
130   }
131
132   if ( shm->physical_address == 0xffffffff )
133     device_error(me, "Address not specified\n" );
134
135   if ( shm->sizeof_memory == 0xffffffff )
136     device_error(me, "Length not specified\n" );
137
138   /* Now actually attach to or create the shared memory area */
139   shm->id = shmget(shm->key, shm->sizeof_memory, IPC_CREAT | 0660);
140   if (shm->id == -1)
141     error("hw_shm_init_data() shmget failed\n");
142
143   shm->shm_address = shmat(shm->id, (char *)0, SHM_RND);
144   if (shm->shm_address == (void *)-1)
145     error("hw_shm_init_data() shmat failed\n");
146 }
147
148 static void
149 hw_shm_attach_address_callback(device *me,
150                                 attach_type attach,
151                                 int space,
152                                 unsigned_word addr,
153                                 unsigned nr_bytes,
154                                 access_type access,
155                                 device *client) /*callback/default*/
156 {
157   hw_shm_device *shm = (hw_shm_device*)device_data(me);
158
159   if (space != 0)
160     error("shm_attach_address_callback() invalid address space\n");
161
162   if (nr_bytes == 0)
163     error("shm_attach_address_callback() invalid size\n");
164 }
165
166
167 static unsigned
168 hw_shm_io_read_buffer(device *me,
169                          void *dest,
170                          int space,
171                          unsigned_word addr,
172                          unsigned nr_bytes,
173                          cpu *processor,
174                          unsigned_word cia)
175 {
176   hw_shm_device *shm = (hw_shm_device*)device_data(me);
177
178   /* do we need to worry about out of range addresses? */
179
180   DTRACE(shm, ("read %p %x %x %x\n", \
181      shm->shm_address, shm->physical_address, addr, nr_bytes) );
182
183   memcpy(dest, &shm->shm_address[addr - shm->physical_address], nr_bytes);
184   return nr_bytes;
185 }
186
187
188 static unsigned
189 hw_shm_io_write_buffer(device *me,
190                           const void *source,
191                           int space,
192                           unsigned_word addr,
193                           unsigned nr_bytes,
194                           cpu *processor,
195                           unsigned_word cia)
196 {
197   hw_shm_device *shm = (hw_shm_device*)device_data(me);
198
199   /* do we need to worry about out of range addresses? */
200
201   DTRACE(shm, ("write %p %x %x %x\n", \
202      shm->shm_address, shm->physical_address, addr, nr_bytes) );
203
204   memcpy(&shm->shm_address[addr - shm->physical_address], source, nr_bytes);
205   return nr_bytes;
206 }
207
208 static device_callbacks const hw_shm_callbacks = {
209   { generic_device_init_address, hw_shm_init_data },
210   { hw_shm_attach_address_callback, }, /* address */
211   { hw_shm_io_read_buffer,
212     hw_shm_io_write_buffer }, /* IO */
213   { NULL, }, /* DMA */
214   { NULL, }, /* interrupt */
215   { NULL, }, /* unit */
216   NULL,
217 };
218
219 static void *
220 hw_shm_create(const char *name,
221                  const device_unit *unit_address,
222                  const char *args)
223 {
224   hw_shm_device *shm = ZALLOC(hw_shm_device);
225   return shm;
226 }
227
228
229
230 const device_descriptor hw_shm_device_descriptor[] = {
231   { "shm", hw_shm_create, &hw_shm_callbacks },
232   { NULL },
233 };
234
235 #endif /* _HW_SHM_C_ */