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