xref: /netbsd/external/gpl3/gdb/dist/sim/ppc/hw_shm.c (revision 48596154)
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, &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
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