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
hw_shm_init_data(device * me)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, ®) )
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
hw_shm_attach_address_callback(device * me,attach_type attach,int space,unsigned_word addr,unsigned nr_bytes,access_type access,device * client)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
hw_shm_io_read_buffer(device * me,void * dest,int space,unsigned_word addr,unsigned nr_bytes,cpu * processor,unsigned_word cia)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
hw_shm_io_write_buffer(device * me,const void * source,int space,unsigned_word addr,unsigned nr_bytes,cpu * processor,unsigned_word cia)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 *
hw_shm_create(const char * name,const device_unit * unit_address,const char * args)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_ */
236