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, ®) ) 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_ */ 236